From 7f1982df25be96772a46030f9580c6a71d9cfd7e Mon Sep 17 00:00:00 2001 From: hyein Heo <128613248+hye-inA@users.noreply.github.com> Date: Tue, 27 Jan 2026 12:26:44 +0900 Subject: [PATCH 1/3] =?UTF-8?q?feature=20:=20OPIc=20=EC=84=B8=EC=85=98=20?= =?UTF-8?q?=EC=99=84=EB=A3=8C=20=EC=B2=98=EB=A6=AC=20=EB=B0=8F=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=20=EB=A6=AC=ED=8F=AC=ED=8A=B8=20=EC=9D=B4=EB=A9=94?= =?UTF-8?q?=EC=9D=BC=20=EB=B0=9C=EC=86=A1=20=EA=B5=AC=ED=98=84=20(#552)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feature : Speaking Table & Function template.yaml 파일에 추가 (#513) * fix: BadgeRepository 클라이언트 초기화 패턴 통일 - 개별 DynamoDbEnhancedClient 생성 대신 AwsClients.dynamoDbEnhanced() 싱글톤 사용 - 다른 Repository들과 동일한 패턴 적용 - 불필요한 import 제거 Closes #396 * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feat : Speaking 관련 template 람다 함수 및 테이블 추가 --------- Co-authored-by: DDING JOO Co-authored-by: Claude Opus 4.5 * feature : Speaking Table & Function template.yaml 파일에 추가 (#513) * fix: BadgeRepository 클라이언트 초기화 패턴 통일 - 개별 DynamoDbEnhancedClient 생성 대신 AwsClients.dynamoDbEnhanced() 싱글톤 사용 - 다른 Repository들과 동일한 패턴 적용 - 불필요한 import 제거 Closes #396 * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feat : Speaking 관련 template 람다 함수 및 테이블 추가 --------- Co-authored-by: DDING JOO * feature : 말하기 연습 기능 polly 서비스 권한 추가 (#514) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feat : Speaking 관련 template 람다 함수 및 테이블 추가 * feat : 말하기 기능에 polly 서비스 권한 추가 --------- Co-authored-by: DDING JOO Co-authored-by: Claude Opus 4.5 * feature : 말하기 연습 기능 polly 서비스 권한 추가 (#514) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feat : Speaking 관련 template 람다 함수 및 테이블 추가 * feat : 말하기 기능에 polly 서비스 권한 추가 --------- Co-authored-by: DDING JOO * feature : transcribe API KEY 추가 (#516) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feat : Speaking 관련 template 람다 함수 및 테이블 추가 * feat : 말하기 기능에 polly 서비스 권한 추가 * feat : transcribe API KEY 추가 --------- Co-authored-by: DDING JOO Co-authored-by: Claude Opus 4.5 * feature : transcribe API KEY 추가 (#516) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feat : Speaking 관련 template 람다 함수 및 테이블 추가 * feat : 말하기 기능에 polly 서비스 권한 추가 * feat : transcribe API KEY 추가 --------- Co-authored-by: DDING JOO * feat: 채팅 슬래시 명령어 시스템 고도화 - 게임 관련 명령어 제거 (/start, /stop, /score, /skip, /hint) - 기본 명령어 추가: /help, /members, /leave, /clear - 재미 명령어 추가: /dice, /coin, /random - 투표 시스템 구현: /poll, /vote, /endpoll - Poll 모델 및 PollRepository 추가 - MessageType에 POLL_CREATE, POLL_VOTE, POLL_END 추가 Closes #518, #519, #520 * feature : Test 브랜치 코드 Prod 브랜치 병합 (#529) * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add real-time notification system with SNS/SQS and Lambda Streaming - Add NotificationTopic and NotificationQueue SNS/SQS infrastructure - Implement NotificationPublisher service for publishing notifications - Create NotificationStreamHandler for SSE via Lambda Function URL - Integrate badge earned notifications in BadgeService - Add daily study completion notifications in DailyStudyCommandService - Add test/quiz result notifications in TestCommandService and NewsQuizService - Add SQS client to AwsClients and JsonUtil helper methods Closes #500, #501, #502, #505, #506 * feat: add streak reminder and game end notifications * refactor: extract config classes and apply DRY principle to news/notification domains * test: add Spock specs for notification and news domain configs * feature : Speaking Table & Function template.yaml 파일에 추가 (#513) * fix: BadgeRepository 클라이언트 초기화 패턴 통일 - 개별 DynamoDbEnhancedClient 생성 대신 AwsClients.dynamoDbEnhanced() 싱글톤 사용 - 다른 Repository들과 동일한 패턴 적용 - 불필요한 import 제거 Closes #396 * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feat : Speaking 관련 template 람다 함수 및 테이블 추가 --------- Co-authored-by: DDING JOO * feature : 말하기 연습 기능 polly 서비스 권한 추가 (#514) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 … * feat: implement word chain (끝말잇기) game with dictionary API integration - Add WordChainSession model with time limit, scoring, player management - Add WordChainService with game logic (start, submit, timeout, stop) - Add DictionaryService for word validation via Free Dictionary API - Add WordChainHandler REST API endpoints (/wordchain/start, submit, etc.) - Add WordChainFunction to SAM template - Add WORDCHAIN_* message types for WebSocket broadcasts - Fix command result domain (use chat domain for chat commands) - Add unit tests for WordChainSession and DictionaryService Closes #524, #525, #526, #527, #528 * fix: update ChattingErrorCodeSpec to include new error codes * fix: add UserTable read permission to WebSocket Lambda WebSocket Lambda needs DynamoDBReadPolicy for UserTable to look up user nicknames for chat commands (/member, /dice, /coin, /hint, etc.) * fix: add Bedrock permission to NewsCollectionFunction NewsCollectionFunction needs bedrock:InvokeModel permission to analyze news difficulty using Claude. * fix: fallback to yesterday's news when today's news is empty GET /news now returns yesterday's articles if no articles exist for today. This prevents empty results before the daily 18:00 KST news collection runs. * feature : 채팅 메뉴에서 닉네임 조회 테스트 배포 (#535) * fix: add Bedrock permission to NewsCollectionFunction NewsCollectionFunction needs bedrock:InvokeModel permission to analyze news difficulty using AI. * fix: fallback to yesterday's news when today's news is empty GET /news now returns yesterday's articles if no articles exist for today. This prevents empty results before the daily 18:00 KST news collection runs. * feature : 채팅 도메인 닉네임 조회용 메서드 추가 (#534) * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feature : Speaking Table & Function template.yaml 파일에 추가 (#513) * fix: BadgeRepository 클라이언트 초기화 패턴 통일 - 개별 DynamoDbEnhancedClient 생성 대신 AwsClients.dynamoDbEnhanced() 싱글톤 사용 - 다른 Repository들과 동일한 패턴 적용 - 불필요한 import 제거 Closes #396 * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 … * fix: revert buildspec to build+package only, let Deploy stage handle deployment - Remove sam deploy from buildspec-test.yml and buildspec-prod.yml - CodeBuild only does sam build + sam package - Deploy stage handles CloudFormation deployment with Cognito parameters * fix: force Authorizer recreation to update Cognito User Pool * fix: rename Authorizer to CognitoAuthV2 to force recreation with correct User Pool * fix: use GSI1 index for WordChainSession roomId queries findActiveByRoomId was querying main table with ROOM#roomId partition key, but the main table PK is WORDCHAIN#sessionId. Fixed to use GSI1 index which has ROOM#roomId as partition key. * feat : SES 클라이언트 의존성 추가 * feat : OPIc 람다에 SES 권한 추가 * feat : OPIc 세션 리포트 이메일 발송 서비스 추가 --------- Co-authored-by: ddingjoo Co-authored-by: Claude Opus 4.5 --- ServerlessFunction/build.gradle | 1 + .../serverless/common/config/AwsClients.java | 8 + .../opic/handler/OPIcSessionHandler.java | 19 ++ .../domain/opic/service/EmailService.java | 294 ++++++++++++++++++ ServerlessFunction/template.yaml | 7 + 5 files changed, 329 insertions(+) create mode 100644 ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/service/EmailService.java diff --git a/ServerlessFunction/build.gradle b/ServerlessFunction/build.gradle index 34615a92..b8f86d93 100644 --- a/ServerlessFunction/build.gradle +++ b/ServerlessFunction/build.gradle @@ -36,6 +36,7 @@ dependencies { implementation 'software.amazon.awssdk:ssm' implementation 'software.amazon.awssdk:scheduler' implementation 'software.amazon.awssdk:sqs' + implementation 'software.amazon.awssdk:ses' // AWS X-Ray SDK (다운스트림 서비스 추적용) implementation 'com.amazonaws:aws-xray-recorder-sdk-core:2.15.0' diff --git a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/common/config/AwsClients.java b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/common/config/AwsClients.java index a1d2286b..0b7416ba 100644 --- a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/common/config/AwsClients.java +++ b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/common/config/AwsClients.java @@ -10,6 +10,7 @@ import software.amazon.awssdk.services.polly.PollyClient; import software.amazon.awssdk.services.s3.S3Client; import software.amazon.awssdk.services.s3.presigner.S3Presigner; +import software.amazon.awssdk.services.ses.SesClient; import software.amazon.awssdk.services.sns.SnsClient; import software.amazon.awssdk.services.sqs.SqsClient; import software.amazon.awssdk.services.ssm.SsmClient; @@ -67,6 +68,11 @@ public final class AwsClients { .overrideConfiguration(XRAY_CONFIG) .build(); + // SES + private static final SesClient SES_CLIENT = SesClient.builder() + .overrideConfiguration(XRAY_CONFIG) + .build(); + private AwsClients() { // 인스턴스화 방지 } @@ -114,4 +120,6 @@ public static SsmClient ssm() { public static SqsClient sqs() { return SQS_CLIENT; } + + public static SesClient ses() { return SES_CLIENT; } } diff --git a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java index cd7335d4..659ba648 100644 --- a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java +++ b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java @@ -7,6 +7,7 @@ import com.google.gson.*; import com.mzc.secondproject.serverless.common.config.AwsClients; import com.mzc.secondproject.serverless.common.service.PollyService; +import com.mzc.secondproject.serverless.common.util.CognitoUtil; import com.mzc.secondproject.serverless.common.util.JwtUtil; import com.mzc.secondproject.serverless.common.util.ResponseGenerator; import com.mzc.secondproject.serverless.domain.opic.dto.request.CreateSessionRequest; @@ -18,6 +19,7 @@ import com.mzc.secondproject.serverless.domain.opic.model.OPIcQuestion; import com.mzc.secondproject.serverless.domain.opic.model.OPIcSession; import com.mzc.secondproject.serverless.domain.opic.repository.OPIcRepository; +import com.mzc.secondproject.serverless.domain.opic.service.EmailService; import com.mzc.secondproject.serverless.domain.opic.service.FeedbackService; import com.mzc.secondproject.serverless.domain.opic.service.TranscribeProxyService; import org.slf4j.Logger; @@ -52,12 +54,15 @@ public class OPIcSessionHandler implements RequestHandler"); + html.append(""); + html.append(""); + + // Header + html.append("
"); + html.append("

🎯 OPIc 스피킹 테스트 결과

"); + html.append("
"); + + // Main Content + html.append("
"); + + // Greeting + html.append("

안녕하세요, ") + .append(userName != null ? userName : "학습자") + .append("님!

"); + html.append("

OPIc 스피킹 테스트 결과를 알려드립니다.

"); + + // Score Cards + html.append("
"); + + // Estimated Level + html.append("
"); + html.append("

예상 등급

"); + html.append("

") + .append(report.estimatedLevel()).append("

"); + html.append("
"); + + // Overall Score + html.append("
"); + html.append("

종합 점수

"); + html.append("

") + .append(report.overallScore()).append("

"); + html.append("
"); + + html.append("
"); + + // Feedback + html.append("
"); + html.append("

📝 종합 피드백

"); + html.append("

") + .append(report.feedback()).append("

"); + html.append("
"); + + // Strengths + html.append("
"); + html.append("

💪 잘한 점

"); + html.append("
    "); + for (String strength : report.strengths()) { + html.append("
  • ").append(strength).append("
  • "); + } + html.append("
"); + html.append("
"); + + // Weaknesses + html.append("
"); + html.append("

📈 개선할 점

"); + html.append("
    "); + for (String weakness : report.weaknesses()) { + html.append("
  • ").append(weakness).append("
  • "); + } + html.append("
"); + html.append("
"); + + // Recommendations + html.append("
"); + html.append("

💡 학습 추천

"); + html.append("
    "); + for (String rec : report.recommendations()) { + html.append("
  1. ").append(rec).append("
  2. "); + } + html.append("
"); + html.append("
"); + + // CTA Button + html.append("
"); + html.append(""); + html.append("전체 리포트 보기"); + html.append("
"); + + // Footer + html.append("
"); + html.append("

"); + html.append("본 이메일은 English Study 서비스에서 자동으로 발송되었습니다.
"); + html.append("© 2025 English Study. All rights reserved.

"); + + html.append("
"); + html.append(""); + + return html.toString(); + } + + /** + * OPIc 리포트 텍스트 버전 (HTML 미지원 이메일 클라이언트용) + */ + private String buildOPIcReportText(String userName, SessionReportResponse report) { + StringBuilder text = new StringBuilder(); + + text.append("OPIc 스피킹 테스트 결과\n"); + text.append("================================\n\n"); + + text.append("안녕하세요, ").append(userName != null ? userName : "학습자").append("님!\n"); + text.append("OPIc 스피킹 테스트 결과를 알려드립니다.\n\n"); + + text.append("결과 요약\n"); + text.append("------------\n"); + text.append("예상 등급: ").append(report.estimatedLevel()).append("\n"); + text.append("종합 점수: ").append(report.overallScore()).append("점\n\n"); + + text.append("종합 피드백\n"); + text.append("------------\n"); + text.append(report.feedback()).append("\n\n"); + + text.append("잘한 점\n"); + text.append("------------\n"); + for (String strength : report.strengths()) { + text.append("• ").append(strength).append("\n"); + } + text.append("\n"); + + text.append("개선할 점\n"); + text.append("------------\n"); + for (String weakness : report.weaknesses()) { + text.append("• ").append(weakness).append("\n"); + } + text.append("\n"); + + text.append("학습 추천\n"); + text.append("------------\n"); + int i = 1; + for (String rec : report.recommendations()) { + text.append(i++).append(". ").append(rec).append("\n"); + } + text.append("\n"); + + text.append("================================\n"); + text.append("© 2025 English Study\n"); + + return text.toString(); + } + + /** + * 레벨별 색상 반환 + */ + private String getLevelColor(String level) { + return switch (level) { + case "NL", "NM", "NH" -> "#6b7280"; + case "IL" -> "#22c55e"; + case "IM1" -> "#10b981"; + case "IM2" -> "#3b82f6"; + case "IM3" -> "#8b5cf6"; + case "IH" -> "#f97316"; + case "AL" -> "#ef4444"; + default -> "#3b82f6"; + }; + } + + /** + * 점수별 색상 반환 + */ + private String getScoreColor(int score) { + if (score >= 90) return "#059669"; + if (score >= 70) return "#3b82f6"; + if (score >= 50) return "#f97316"; + return "#ef4444"; + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ServerlessFunction/template.yaml b/ServerlessFunction/template.yaml index ed741aeb..7b0e54bb 100644 --- a/ServerlessFunction/template.yaml +++ b/ServerlessFunction/template.yaml @@ -48,6 +48,7 @@ Globals: AWS_REGION_NAME: !Ref AWS::Region ROOM_TOKEN_TTL_SECONDS: "300" TRANSCRIBE_PROXY_URL: "https://tfo1zm7vec.execute-api.ap-northeast-2.amazonaws.com/prod/transcribe" + SES_SENDER_EMAIL: "hye.ina0130@gmail.com" Api: TracingEnabled: true @@ -1553,6 +1554,12 @@ Resources: Action: - ssm:GetParameter Resource: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/opic/*" + - Statement: + - Effect: Allow + Action: + - ses:SendEmail + - ses:SendRawEmail + Resource: "*" - SNSPublishMessagePolicy: TopicName: !GetAtt NotificationTopic.TopicName Events: From 4e0dfad032d91b0edcde6d3c8c6a9a4ddeac17b6 Mon Sep 17 00:00:00 2001 From: hyein Heo <128613248+hye-inA@users.noreply.github.com> Date: Tue, 27 Jan 2026 16:20:26 +0900 Subject: [PATCH 2/3] =?UTF-8?q?refactor=20:=20OPIc=20=EB=8B=B5=EB=B3=80=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EB=B9=84=EB=8F=99=EA=B8=B0=ED=99=94(SNS+P?= =?UTF-8?q?olling)=20=EB=B0=8F=20=EB=A6=AC=ED=8F=AC=ED=8A=B8=20=EC=9D=B4?= =?UTF-8?q?=EB=A9=94=EC=9D=BC=20=EB=B0=9C=EC=86=A1=20=EA=B5=AC=ED=98=84=20?= =?UTF-8?q?(#555)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feature : Speaking Table & Function template.yaml 파일에 추가 (#513) * fix: BadgeRepository 클라이언트 초기화 패턴 통일 - 개별 DynamoDbEnhancedClient 생성 대신 AwsClients.dynamoDbEnhanced() 싱글톤 사용 - 다른 Repository들과 동일한 패턴 적용 - 불필요한 import 제거 Closes #396 * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feat : Speaking 관련 template 람다 함수 및 테이블 추가 --------- Co-authored-by: DDING JOO Co-authored-by: Claude Opus 4.5 * feature : Speaking Table & Function template.yaml 파일에 추가 (#513) * fix: BadgeRepository 클라이언트 초기화 패턴 통일 - 개별 DynamoDbEnhancedClient 생성 대신 AwsClients.dynamoDbEnhanced() 싱글톤 사용 - 다른 Repository들과 동일한 패턴 적용 - 불필요한 import 제거 Closes #396 * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feat : Speaking 관련 template 람다 함수 및 테이블 추가 --------- Co-authored-by: DDING JOO * feature : 말하기 연습 기능 polly 서비스 권한 추가 (#514) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feat : Speaking 관련 template 람다 함수 및 테이블 추가 * feat : 말하기 기능에 polly 서비스 권한 추가 --------- Co-authored-by: DDING JOO Co-authored-by: Claude Opus 4.5 * feature : 말하기 연습 기능 polly 서비스 권한 추가 (#514) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feat : Speaking 관련 template 람다 함수 및 테이블 추가 * feat : 말하기 기능에 polly 서비스 권한 추가 --------- Co-authored-by: DDING JOO * feature : transcribe API KEY 추가 (#516) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feat : Speaking 관련 template 람다 함수 및 테이블 추가 * feat : 말하기 기능에 polly 서비스 권한 추가 * feat : transcribe API KEY 추가 --------- Co-authored-by: DDING JOO Co-authored-by: Claude Opus 4.5 * feature : transcribe API KEY 추가 (#516) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feat : Speaking 관련 template 람다 함수 및 테이블 추가 * feat : 말하기 기능에 polly 서비스 권한 추가 * feat : transcribe API KEY 추가 --------- Co-authored-by: DDING JOO * feat: 채팅 슬래시 명령어 시스템 고도화 - 게임 관련 명령어 제거 (/start, /stop, /score, /skip, /hint) - 기본 명령어 추가: /help, /members, /leave, /clear - 재미 명령어 추가: /dice, /coin, /random - 투표 시스템 구현: /poll, /vote, /endpoll - Poll 모델 및 PollRepository 추가 - MessageType에 POLL_CREATE, POLL_VOTE, POLL_END 추가 Closes #518, #519, #520 * feature : Test 브랜치 코드 Prod 브랜치 병합 (#529) * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add real-time notification system with SNS/SQS and Lambda Streaming - Add NotificationTopic and NotificationQueue SNS/SQS infrastructure - Implement NotificationPublisher service for publishing notifications - Create NotificationStreamHandler for SSE via Lambda Function URL - Integrate badge earned notifications in BadgeService - Add daily study completion notifications in DailyStudyCommandService - Add test/quiz result notifications in TestCommandService and NewsQuizService - Add SQS client to AwsClients and JsonUtil helper methods Closes #500, #501, #502, #505, #506 * feat: add streak reminder and game end notifications * refactor: extract config classes and apply DRY principle to news/notification domains * test: add Spock specs for notification and news domain configs * feature : Speaking Table & Function template.yaml 파일에 추가 (#513) * fix: BadgeRepository 클라이언트 초기화 패턴 통일 - 개별 DynamoDbEnhancedClient 생성 대신 AwsClients.dynamoDbEnhanced() 싱글톤 사용 - 다른 Repository들과 동일한 패턴 적용 - 불필요한 import 제거 Closes #396 * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feat : Speaking 관련 template 람다 함수 및 테이블 추가 --------- Co-authored-by: DDING JOO * feature : 말하기 연습 기능 polly 서비스 권한 추가 (#514) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 … * feat: implement word chain (끝말잇기) game with dictionary API integration - Add WordChainSession model with time limit, scoring, player management - Add WordChainService with game logic (start, submit, timeout, stop) - Add DictionaryService for word validation via Free Dictionary API - Add WordChainHandler REST API endpoints (/wordchain/start, submit, etc.) - Add WordChainFunction to SAM template - Add WORDCHAIN_* message types for WebSocket broadcasts - Fix command result domain (use chat domain for chat commands) - Add unit tests for WordChainSession and DictionaryService Closes #524, #525, #526, #527, #528 * fix: update ChattingErrorCodeSpec to include new error codes * fix: add UserTable read permission to WebSocket Lambda WebSocket Lambda needs DynamoDBReadPolicy for UserTable to look up user nicknames for chat commands (/member, /dice, /coin, /hint, etc.) * fix: add Bedrock permission to NewsCollectionFunction NewsCollectionFunction needs bedrock:InvokeModel permission to analyze news difficulty using Claude. * fix: fallback to yesterday's news when today's news is empty GET /news now returns yesterday's articles if no articles exist for today. This prevents empty results before the daily 18:00 KST news collection runs. * feature : 채팅 메뉴에서 닉네임 조회 테스트 배포 (#535) * fix: add Bedrock permission to NewsCollectionFunction NewsCollectionFunction needs bedrock:InvokeModel permission to analyze news difficulty using AI. * fix: fallback to yesterday's news when today's news is empty GET /news now returns yesterday's articles if no articles exist for today. This prevents empty results before the daily 18:00 KST news collection runs. * feature : 채팅 도메인 닉네임 조회용 메서드 추가 (#534) * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feature : Speaking Table & Function template.yaml 파일에 추가 (#513) * fix: BadgeRepository 클라이언트 초기화 패턴 통일 - 개별 DynamoDbEnhancedClient 생성 대신 AwsClients.dynamoDbEnhanced() 싱글톤 사용 - 다른 Repository들과 동일한 패턴 적용 - 불필요한 import 제거 Closes #396 * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 … * fix: revert buildspec to build+package only, let Deploy stage handle deployment - Remove sam deploy from buildspec-test.yml and buildspec-prod.yml - CodeBuild only does sam build + sam package - Deploy stage handles CloudFormation deployment with Cognito parameters * fix: force Authorizer recreation to update Cognito User Pool * fix: rename Authorizer to CognitoAuthV2 to force recreation with correct User Pool * fix: use GSI1 index for WordChainSession roomId queries findActiveByRoomId was querying main table with ROOM#roomId partition key, but the main table PK is WORDCHAIN#sessionId. Fixed to use GSI1 index which has ROOM#roomId as partition key. * feat : SES 클라이언트 의존성 추가 * feat : OPIc 람다에 SES 권한 추가 * feat : OPIc 세션 리포트 이메일 발송 서비스 추가 * refactor : 오픽 답변 비동기 처리 --------- Co-authored-by: ddingjoo Co-authored-by: Claude Opus 4.5 --- .../opic/handler/AnswerProcessHandler.java | 213 +++++++++ .../opic/handler/OPIcSessionHandler.java | 417 ++++++++++-------- ServerlessFunction/template.yaml | 61 ++- 3 files changed, 517 insertions(+), 174 deletions(-) create mode 100644 ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/AnswerProcessHandler.java diff --git a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/AnswerProcessHandler.java b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/AnswerProcessHandler.java new file mode 100644 index 00000000..294c9c8c --- /dev/null +++ b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/AnswerProcessHandler.java @@ -0,0 +1,213 @@ +package com.mzc.secondproject.serverless.domain.opic.handler; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.SNSEvent; +import com.google.gson.Gson; +import com.mzc.secondproject.serverless.common.config.AwsClients; +import com.mzc.secondproject.serverless.domain.opic.dto.response.FeedbackResponse; +import com.mzc.secondproject.serverless.domain.opic.model.OPIcAnswer; +import com.mzc.secondproject.serverless.domain.opic.model.OPIcQuestion; +import com.mzc.secondproject.serverless.domain.opic.model.OPIcSession; +import com.mzc.secondproject.serverless.domain.opic.repository.OPIcRepository; +import com.mzc.secondproject.serverless.domain.opic.service.FeedbackService; +import com.mzc.secondproject.serverless.domain.opic.service.TranscribeProxyService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.time.Instant; +import java.util.Map; + +/** + * SNS 트리거로 답변 비동기 처리 + * - Transcribe (STT) + * - Bedrock 피드백 생성 + * - Answer 상태 업데이트 + */ +public class AnswerProcessHandler implements RequestHandler { + + private static final Logger logger = LoggerFactory.getLogger(AnswerProcessHandler.class); + private static final String OPIC_BUCKET = System.getenv("OPIC_BUCKET_NAME"); + + private final Gson gson = new Gson(); + private final OPIcRepository repository = new OPIcRepository(); + private final TranscribeProxyService transcribeService = new TranscribeProxyService(); + private final FeedbackService feedbackService = new FeedbackService(); + + @Override + public Void handleRequest(SNSEvent event, Context context) { + for (SNSEvent.SNSRecord record : event.getRecords()) { + processMessage(record.getSNS().getMessage()); + } + return null; + } + + @SuppressWarnings("unchecked") + private void processMessage(String messageBody) { + Map message = gson.fromJson(messageBody, Map.class); + + String sessionId = (String) message.get("sessionId"); + String questionId = (String) message.get("questionId"); + String audioS3Key = (String) message.get("audioS3Key"); + String targetLevel = (String) message.get("targetLevel"); + int currentIndex = ((Number) message.get("currentIndex")).intValue(); + int totalQuestions = ((Number) message.get("totalQuestions")).intValue(); + + logger.info("비동기 처리 시작: sessionId={}, questionIndex={}", sessionId, currentIndex); + + try { + // Answer 조회 (sessionId + questionIndex로 조회) + OPIcAnswer answer = repository.findAnswer(sessionId, currentIndex) + .orElseThrow(() -> new RuntimeException( + String.format("Answer not found: sessionId=%s, questionIndex=%d", sessionId, currentIndex))); + + // Question 조회 + OPIcQuestion question = repository.findQuestionById(questionId) + .orElseThrow(() -> new RuntimeException("Question not found: " + questionId)); + + // 1. S3에서 오디오 로드 + logger.info("S3에서 오디오 파일 로드: {}", audioS3Key); + byte[] audioBytes = AwsClients.s3().getObjectAsBytes( + software.amazon.awssdk.services.s3.model.GetObjectRequest.builder() + .bucket(OPIC_BUCKET) + .key(audioS3Key) + .build() + ).asByteArray(); + + String audioBase64 = java.util.Base64.getEncoder().encodeToString(audioBytes); + logger.info("오디오 Base64 변환: {} bytes → {} chars", audioBytes.length, audioBase64.length()); + + // 2. Transcribe (STT) + TranscribeProxyService.TranscribeResult transcribeResult = + transcribeService.transcribe(audioBase64, sessionId); + + String transcript = transcribeResult.transcript(); + logger.info("STT 완료: transcript 길이={}", transcript.length()); + + // 3. Bedrock 피드백 + FeedbackResponse feedback = feedbackService.generateFeedback( + question.getQuestionText(), + transcript, + targetLevel + ); + logger.info("피드백 생성 완료"); + + // 4. Answer 업데이트 (COMPLETED) + answer.setQuestionText(question.getQuestionText()); + answer.setTranscript(transcript); + answer.setTranscriptConfidence(transcribeResult.confidence()); + answer.setGrammarFeedback(gson.toJson(feedback.errors())); + answer.setContentFeedback(feedback.correctedAnswer()); + answer.setSampleAnswer(feedback.sampleAnswer()); + answer.setStatus(OPIcAnswer.AnswerStatus.COMPLETED); + answer.setAttemptCount(answer.getAttemptCount() + 1); + answer.setCompletedAt(Instant.now()); + + repository.saveAnswer(answer); + + // 5. 세션 업데이트 (currentQuestionIndex 증가) + OPIcSession session = repository.findSessionById(sessionId).orElse(null); + if (session != null) { + session.setCurrentQuestionIndex(currentIndex + 1); + repository.updateSession(session); + } + + logger.info("비동기 처리 완료: sessionId={}, questionIndex={}", sessionId, currentIndex); + + } catch (Exception e) { + logger.error("비동기 처리 실패: sessionId={}, questionIndex={}, error={}", + sessionId, currentIndex, e.getMessage(), e); + + // 실패 상태로 업데이트 + try { + OPIcAnswer answer = repository.findAnswer(sessionId, currentIndex).orElse(null); + if (answer != null) { + answer.setStatus(OPIcAnswer.AnswerStatus.FAILED); + answer.setAttemptCount(answer.getAttemptCount() + 1); + repository.saveAnswer(answer); + logger.info("Answer 상태 FAILED로 업데이트: sessionId={}, questionIndex={}", sessionId, currentIndex); + } + } catch (Exception ex) { + logger.error("실패 상태 업데이트 실패", ex); + } + } + } +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java index 659ba648..c79576d2 100644 --- a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java +++ b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import software.amazon.awssdk.services.s3.model.PutObjectRequest; import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest; +import software.amazon.awssdk.services.sns.model.PublishRequest; import java.lang.reflect.Type; import java.time.Duration; @@ -37,26 +38,26 @@ * OPIc 세션 통합 Handler * - 세션 생성/조회 * - 질문 조회 (Polly 음성 URL 포함) - * - 답변 제출 (Transcribe + Bedrock 피드백) + * - 답변 제출 (비동기: SNS → AnswerProcessHandler) + * - 답변 상태 조회 (폴링) * - 세션 완료 (종합 리포트) */ public class OPIcSessionHandler implements RequestHandler { - + private static final Logger logger = LoggerFactory.getLogger(OPIcSessionHandler.class); private static final Gson gson = new GsonBuilder() .setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") .registerTypeAdapter(Instant.class, new InstantTypeAdapter()) .create(); - + private static final String OPIC_BUCKET = System.getenv("OPIC_BUCKET_NAME"); - + private final OPIcRepository repository; private final PollyService pollyService; private final TranscribeProxyService transcribeService; private final FeedbackService feedbackService; - private final EmailService emailService; - + public OPIcSessionHandler() { this.repository = new OPIcRepository(); this.pollyService = new PollyService(OPIC_BUCKET, "opic/voice/questions/"); @@ -64,62 +65,65 @@ public OPIcSessionHandler() { this.feedbackService = new FeedbackService(); this.emailService = new EmailService(); } - + @Override public APIGatewayProxyResponseEvent handleRequest(APIGatewayProxyRequestEvent event, Context context) { String httpMethod = event.getHttpMethod(); String path = event.getPath(); - + try { - String userId = extractUserId(event); - - + // POST /opic/sessions - 세션 생성 if ("POST".equals(httpMethod) && path.equals("/opic/sessions")) { return createSession(event, userId); } - + // GET /opic/sessions - 세션 목록 조회 if ("GET".equals(httpMethod) && path.equals("/opic/sessions")) { return getSessions(userId); } - + // GET /opic/sessions/{sessionId} - 세션 상세 조회 if ("GET".equals(httpMethod) && path.matches("/opic/sessions/[^/]+") - && !path.contains("/questions") && !path.contains("/upload-url")) { + && !path.contains("/questions") && !path.contains("/upload-url") && !path.contains("/answers")) { return getSession(event, userId); } - + // GET /opic/sessions/{sessionId}/questions/next - 다음 질문 조회 if ("GET".equals(httpMethod) && path.contains("/questions/next")) { return getNextQuestion(event, userId); } - + // GET /opic/sessions/{sessionId}/upload-url - Presigned URL 발급 if ("GET".equals(httpMethod) && path.contains("/upload-url")) { return getUploadUrl(event, userId); } - - // POST /opic/sessions/{sessionId}/answers - 답변 제출 + + // POST /opic/sessions/{sessionId}/answers - 답변 제출 (비동기) if ("POST".equals(httpMethod) && path.contains("/answers")) { return submitAnswer(event, userId); } - + + // GET /opic/sessions/{sessionId}/answers/{questionIndex}/status - 답변 상태 조회 (폴링) + if ("GET".equals(httpMethod) && path.matches(".*/answers/\\d+/status")) { + return getAnswerStatus(event, userId); + } + // POST /opic/sessions/{sessionId}/complete - 세션 완료 if ("POST".equals(httpMethod) && path.contains("/complete")) { return completeSession(event, userId); } - + return ResponseGenerator.badRequest("지원하지 않는 요청입니다: " + httpMethod + " " + path); - + } catch (Exception e) { logger.error("OPIc Handler 에러", e); return ResponseGenerator.serverError(e.getMessage()); } } - - + + /** * POST /opic/sessions * 세션 생성 + 첫 질문 반환 @@ -132,8 +136,8 @@ private APIGatewayProxyResponseEvent createSession(APIGatewayProxyRequestEvent e // 질문 세트 조회 (주제+소주제로 조회) List questions = repository.findQuestionsByTopicAndSubTopic( - request.topic(), // 예: "DESCRIPTION" - request.subTopic() // 예: "HOMES" + request.topic(), + request.subTopic() ); // 질문 데이터 없음 예외 처리 @@ -160,7 +164,7 @@ private APIGatewayProxyResponseEvent createSession(APIGatewayProxyRequestEvent e userId, request.topic(), request.subTopic(), - request.targetLevel(), // 사용자가 선택한 레벨 저장 (AL, IM2 등) + request.targetLevel(), questionIds ); @@ -172,157 +176,159 @@ private APIGatewayProxyResponseEvent createSession(APIGatewayProxyRequestEvent e firstQuestion.getQuestionId(), firstQuestion.getQuestionText(), audioUrl, - 1, // 현재 질문 번호 - 3 // 총 질문 수 + 1, + 3 ); return ResponseGenerator.ok( new CreateSessionResponse(session.getSessionId(), questionResponse, 3) ); } - + /** * GET /opic/sessions * 사용자의 세션 목록 조회 */ private APIGatewayProxyResponseEvent getSessions(String userId) { List sessions = repository.findSessionsByUserId(userId, 20); - + Map responseBody = new LinkedHashMap<>(); responseBody.put("isSuccess", true); responseBody.put("data", sessions); - + return new APIGatewayProxyResponseEvent() .withStatusCode(200) .withHeaders(Map.of("Content-Type", "application/json")) .withBody(gson.toJson(responseBody)); } - + /** * GET /opic/sessions/{sessionId} * 세션 상세 조회 */ private APIGatewayProxyResponseEvent getSession(APIGatewayProxyRequestEvent event, String userId) { String sessionId = event.getPathParameters().get("sessionId"); - + OPIcSession session = repository.findSessionById(sessionId).orElse(null); - + if (session == null) { return ResponseGenerator.notFound("세션을 찾을 수 없습니다."); } - + if (!session.getUserId().equals(userId)) { return ResponseGenerator.forbidden("접근 권한이 없습니다."); } - + // 세션에 포함된 답변들도 조회 List answers = repository.findAnswersBySessionId(sessionId); - + Map response = new LinkedHashMap<>(); response.put("session", session); response.put("answers", answers); - + return ResponseGenerator.ok(response); } - + /** * GET /opic/sessions/{sessionId}/questions/next * 다음 질문 조회 (Polly 음성 URL 포함) */ private APIGatewayProxyResponseEvent getNextQuestion(APIGatewayProxyRequestEvent event, String userId) { String sessionId = event.getPathParameters().get("sessionId"); - + OPIcSession session = repository.findSessionById(sessionId).orElse(null); - + if (session == null) { return ResponseGenerator.notFound("세션을 찾을 수 없습니다."); } - + if (!session.getUserId().equals(userId)) { return ResponseGenerator.forbidden("접근 권한이 없습니다."); } - - // 모든 질문 완료 확인 + int currentIndex = session.getCurrentQuestionIndex(); + + // 모든 질문 완료 확인 if (currentIndex >= session.getTotalQuestions()) { - return ResponseGenerator.ok(Map.of( - "completed", true, - "message", "모든 질문이 완료되었습니다. 세션을 완료해주세요.", - "sessionId", sessionId - )); + Map response = new LinkedHashMap<>(); + response.put("completed", true); + response.put("message", "모든 질문이 완료되었습니다. 세션을 완료해주세요."); + return ResponseGenerator.ok(response); } - + // 다음 질문 조회 String questionId = session.getQuestionIds().get(currentIndex); OPIcQuestion question = repository.findQuestionById(questionId) - .orElseThrow(() -> new RuntimeException("질문을 찾을 수 없습니다: " + questionId)); - - // Polly 음성 URL + .orElseThrow(() -> new RuntimeException("질문을 찾을 수 없습니다.")); + String audioUrl = generateQuestionAudioUrl(question); - + + QuestionResponse questionResponse = new QuestionResponse( + question.getQuestionId(), + question.getQuestionText(), + audioUrl, + currentIndex + 1, + session.getTotalQuestions() + ); + Map response = new LinkedHashMap<>(); - response.put("questionId", question.getQuestionId()); - response.put("questionText", question.getQuestionText()); - response.put("audioUrl", audioUrl); - response.put("questionNumber", currentIndex + 1); - response.put("totalQuestions", session.getTotalQuestions()); - response.put("completed", false); - + response.put("question", questionResponse); + response.put("hasNextQuestion", (currentIndex + 1) < session.getTotalQuestions()); + return ResponseGenerator.ok(response); } - + /** * GET /opic/sessions/{sessionId}/upload-url - * S3 Presigned URL 발급 (음성 업로드용) + * Presigned URL 발급 */ private APIGatewayProxyResponseEvent getUploadUrl(APIGatewayProxyRequestEvent event, String userId) { String sessionId = event.getPathParameters().get("sessionId"); - - // 세션 검증 + OPIcSession session = repository.findSessionById(sessionId).orElse(null); - if (session == null || !session.getUserId().equals(userId)) { + if (session == null) { + return ResponseGenerator.notFound("세션을 찾을 수 없습니다."); + } + if (!session.getUserId().equals(userId)) { return ResponseGenerator.forbidden("접근 권한이 없습니다."); } - - // S3 키 생성 - String s3Key = String.format("opic/answers/%s/%s/%s.webm", - userId, - sessionId, - UUID.randomUUID().toString() - ); - - // Presigned URL 생성 (5분 유효) - PutObjectRequest putRequest = PutObjectRequest.builder() + + String fileId = UUID.randomUUID().toString(); + String s3Key = String.format("opic/answers/%s/%s/%s.webm", userId, sessionId, fileId); + + PutObjectRequest putObjectRequest = PutObjectRequest.builder() .bucket(OPIC_BUCKET) .key(s3Key) .contentType("audio/webm") .build(); - - String presignedUrl = AwsClients.s3Presigner() - .presignPutObject(PutObjectPresignRequest.builder() - .putObjectRequest(putRequest) - .signatureDuration(Duration.ofMinutes(5)) - .build()) + + PutObjectPresignRequest presignRequest = PutObjectPresignRequest.builder() + .putObjectRequest(putObjectRequest) + .signatureDuration(Duration.ofMinutes(10)) + .build(); + + String uploadUrl = AwsClients.s3Presigner() + .presignPutObject(presignRequest) .url() .toString(); - - return ResponseGenerator.ok(Map.of( - "uploadUrl", presignedUrl, - "s3Key", s3Key, - "expiresIn", 300 - )); + + Map response = new LinkedHashMap<>(); + response.put("uploadUrl", uploadUrl); + response.put("s3Key", s3Key); + + return ResponseGenerator.ok(response); } - + /** * POST /opic/sessions/{sessionId}/answers - * 답변 제출 → STT → AI 피드백 + * 답변 제출 (비동기 - SNS로 처리 위임) */ private APIGatewayProxyResponseEvent submitAnswer(APIGatewayProxyRequestEvent event, String userId) { String sessionId = event.getPathParameters().get("sessionId"); SubmitAnswerRequest request = gson.fromJson(event.getBody(), SubmitAnswerRequest.class); - - logger.info("답변 제출: sessionId={}, s3Key={}", sessionId, request.audioS3Key()); - + + logger.info("답변 제출 (비동기): sessionId={}, s3Key={}", sessionId, request.audioS3Key()); + // 세션 검증 OPIcSession session = repository.findSessionById(sessionId).orElse(null); if (session == null) { @@ -331,95 +337,154 @@ private APIGatewayProxyResponseEvent submitAnswer(APIGatewayProxyRequestEvent ev if (!session.getUserId().equals(userId)) { return ResponseGenerator.forbidden("접근 권한이 없습니다."); } - - // 현재 질문 조회 + + // 현재 질문 인덱스 확인 int currentIndex = session.getCurrentQuestionIndex(); if (currentIndex >= session.getTotalQuestions()) { return ResponseGenerator.badRequest("이미 모든 질문에 답변했습니다."); } - + String questionId = session.getQuestionIds().get(currentIndex); - OPIcQuestion question = repository.findQuestionById(questionId) - .orElseThrow(() -> new RuntimeException("질문을 찾을 수 없습니다.")); - - // Transcribe Proxy 호출 (음성 → 텍스트) - logger.info("S3에서 오디오 파일 로드: {}", request.audioS3Key()); - - byte[] audioBytes = AwsClients.s3().getObjectAsBytes( - software.amazon.awssdk.services.s3.model.GetObjectRequest.builder() - .bucket(OPIC_BUCKET) - .key(request.audioS3Key()) - .build() - ).asByteArray(); - - String audioBase64 = java.util.Base64.getEncoder().encodeToString(audioBytes); - logger.info("오디오 파일 Base64 변환 완료: {} bytes → {} chars", - audioBytes.length, audioBase64.length()); - - // 4. Transcribe Proxy 호출 (Base64 데이터 전송) - TranscribeProxyService.TranscribeResult transcribeResult = - transcribeService.transcribe(audioBase64, sessionId); - - String transcript = transcribeResult.transcript(); - logger.info("STT 변환 완료: transcript 길이={}", transcript.length()); - - // Bedrock 피드백 생성 - FeedbackResponse feedback = feedbackService.generateFeedback( - question.getQuestionText(), - transcript, - session.getTargetLevel() - ); - - // Answer 저장 - 개별 필드로 분리 저장 + + // Answer 레코드 생성 (PROCESSING 상태) OPIcAnswer answer = new OPIcAnswer(); answer.setSessionId(sessionId); answer.setQuestionId(questionId); answer.setQuestionIndex(currentIndex); - answer.setQuestionText(question.getQuestionText()); // 비정규화 answer.setAudioS3Key(request.audioS3Key()); - answer.setTranscript(transcript); - answer.setTranscriptConfidence(transcribeResult.confidence()); - - // 피드백 개별 필드 저장 - answer.setGrammarFeedback(gson.toJson(feedback.errors())); // errors → grammarFeedback - answer.setContentFeedback(feedback.correctedAnswer()); // correctedAnswer → contentFeedback - answer.setSampleAnswer(feedback.sampleAnswer()); // 모범 답변 - answer.setStatus(OPIcAnswer.AnswerStatus.COMPLETED); - answer.setAttemptCount(1); + answer.setStatus(OPIcAnswer.AnswerStatus.PROCESSING); + answer.setAttemptCount(0); answer.setCreatedAt(Instant.now()); - answer.setCompletedAt(Instant.now()); - + repository.saveAnswer(answer); - - // 세션 진행 상태 업데이트 - session.setCurrentQuestionIndex(currentIndex + 1); - repository.updateSession(session); - - // Response - boolean hasNext = (currentIndex + 1) < session.getTotalQuestions(); - + logger.info("Answer 생성 (PROCESSING): sessionId={}, questionIndex={}", sessionId, currentIndex); + + // SNS로 비동기 처리 요청 + publishToSNS(sessionId, questionId, request.audioS3Key(), + session.getTargetLevel(), currentIndex, session.getTotalQuestions()); + + // 즉시 응답 (HTTP 202 Accepted) Map response = new LinkedHashMap<>(); - response.put("transcript", transcript); + response.put("sessionId", sessionId); + response.put("questionIndex", currentIndex); + response.put("status", "PROCESSING"); + response.put("message", "답변을 처리 중입니다. 잠시 후 결과를 확인하세요."); + response.put("pollingUrl", String.format("/opic/sessions/%s/answers/%d/status", sessionId, currentIndex)); + + return ResponseGenerator.ok(response); + } + + /** + * SNS 발행 (비동기 처리 요청) + */ + private void publishToSNS(String sessionId, String questionId, String audioS3Key, + String targetLevel, int currentIndex, int totalQuestions) { + try { + String topicArn = System.getenv("ANSWER_PROCESS_TOPIC_ARN"); + + if (topicArn == null || topicArn.isEmpty()) { + logger.error("ANSWER_PROCESS_TOPIC_ARN 환경변수가 설정되지 않았습니다."); + return; + } + + Map message = new LinkedHashMap<>(); + message.put("sessionId", sessionId); + message.put("questionId", questionId); + message.put("audioS3Key", audioS3Key); + message.put("targetLevel", targetLevel); + message.put("currentIndex", currentIndex); + message.put("totalQuestions", totalQuestions); + + AwsClients.sns().publish(PublishRequest.builder() + .topicArn(topicArn) + .message(gson.toJson(message)) + .build()); + + logger.info("SNS 발행 완료: sessionId={}, questionIndex={}", sessionId, currentIndex); + } catch (Exception e) { + logger.error("SNS 발행 실패: {}", e.getMessage(), e); + // 실패해도 일단 진행 (폴링에서 PROCESSING 상태로 계속 보임) + } + } + + /** + * GET /opic/sessions/{sessionId}/answers/{questionIndex}/status + * 답변 상태 조회 (폴링용) + */ + private APIGatewayProxyResponseEvent getAnswerStatus(APIGatewayProxyRequestEvent event, String userId) { + String sessionId = event.getPathParameters().get("sessionId"); + String questionIndexStr = event.getPathParameters().get("questionIndex"); + int questionIndex = Integer.parseInt(questionIndexStr); + + logger.info("답변 상태 조회: sessionId={}, questionIndex={}", sessionId, questionIndex); + + // 세션 권한 확인 + OPIcSession session = repository.findSessionById(sessionId).orElse(null); + if (session == null) { + return ResponseGenerator.notFound("세션을 찾을 수 없습니다."); + } + if (!session.getUserId().equals(userId)) { + return ResponseGenerator.forbidden("접근 권한이 없습니다."); + } + + // 답변 조회 + OPIcAnswer answer = repository.findAnswer(sessionId, questionIndex).orElse(null); + if (answer == null) { + return ResponseGenerator.notFound("답변을 찾을 수 없습니다."); + } + + Map response = new LinkedHashMap<>(); + response.put("sessionId", sessionId); + response.put("questionIndex", questionIndex); + response.put("status", answer.getStatus().name()); + + if (answer.getStatus() == OPIcAnswer.AnswerStatus.PROCESSING) { + response.put("message", "아직 처리 중입니다..."); + return ResponseGenerator.ok(response); + } + + if (answer.getStatus() == OPIcAnswer.AnswerStatus.FAILED) { + response.put("message", "처리에 실패했습니다. 다시 시도해주세요."); + return ResponseGenerator.ok(response); + } + + // COMPLETED - 전체 결과 반환 + response.put("transcript", answer.getTranscript()); + + // feedback 객체 구성 + Map feedback = new LinkedHashMap<>(); + if (answer.getGrammarFeedback() != null && !answer.getGrammarFeedback().isEmpty()) { + try { + feedback.put("errors", gson.fromJson(answer.getGrammarFeedback(), List.class)); + } catch (Exception e) { + feedback.put("errors", new ArrayList<>()); + } + } else { + feedback.put("errors", new ArrayList<>()); + } + feedback.put("correctedAnswer", answer.getContentFeedback()); + feedback.put("sampleAnswer", answer.getSampleAnswer()); response.put("feedback", feedback); + + boolean hasNext = (questionIndex + 1) < session.getTotalQuestions(); response.put("hasNextQuestion", hasNext); - response.put("currentQuestion", currentIndex + 1); + response.put("currentQuestion", questionIndex + 1); response.put("totalQuestions", session.getTotalQuestions()); - + if (hasNext) { - response.put("nextQuestionNumber", currentIndex + 2); + response.put("nextQuestionNumber", questionIndex + 2); } - - logger.info("답변 처리 완료: sessionId={}, questionIndex={}", sessionId, currentIndex); - return ResponseGenerator.ok("피드백이 생성되었습니다.", response); + + return ResponseGenerator.ok(response); } - + /** * POST /opic/sessions/{sessionId}/complete * 세션 완료 + 종합 리포트 생성 */ private APIGatewayProxyResponseEvent completeSession(APIGatewayProxyRequestEvent event, String userId) { String sessionId = event.getPathParameters().get("sessionId"); - + OPIcSession session = repository.findSessionById(sessionId).orElse(null); if (session == null) { return ResponseGenerator.notFound("세션을 찾을 수 없습니다."); @@ -427,29 +492,35 @@ private APIGatewayProxyResponseEvent completeSession(APIGatewayProxyRequestEvent if (!session.getUserId().equals(userId)) { return ResponseGenerator.forbidden("접근 권한이 없습니다."); } - + // 모든 질문 답변 완료 확인 List answers = repository.findAnswersBySessionId(sessionId); - if (answers.size() < session.getTotalQuestions()) { + + // COMPLETED 상태인 답변만 카운트 + long completedAnswers = answers.stream() + .filter(a -> a.getStatus() == OPIcAnswer.AnswerStatus.COMPLETED) + .count(); + + if (completedAnswers < session.getTotalQuestions()) { return ResponseGenerator.badRequest( String.format("아직 %d개의 질문에 답변하지 않았습니다.", - session.getTotalQuestions() - answers.size()) + session.getTotalQuestions() - completedAnswers) ); } - + // 세션 요약 생성 (피드백용) StringBuilder summaryBuilder = new StringBuilder(); for (int i = 0; i < answers.size(); i++) { OPIcAnswer answer = answers.get(i); OPIcQuestion question = repository.findQuestionById(answer.getQuestionId()).orElse(null); - + summaryBuilder.append(String.format("### Question %d\n", i + 1)); if (question != null) { summaryBuilder.append("Q: ").append(question.getQuestionText()).append("\n"); } summaryBuilder.append("A: ").append(answer.getTranscript()).append("\n\n"); } - + // 종합 리포트 생성 (Bedrock) var sessionReport = feedbackService.generateSessionReport( summaryBuilder.toString(), @@ -469,22 +540,22 @@ private APIGatewayProxyResponseEvent completeSession(APIGatewayProxyRequestEvent // 이메일 실패해도 세션 완료는 성공 처리 logger.warn("리포트 이메일 발송 실패 (무시됨): {}", e.getMessage()); } - + // 세션 완료 처리 repository.completeSession( session, sessionReport.estimatedLevel(), gson.toJson(sessionReport) ); - + logger.info("세션 완료: sessionId={}, estimatedLevel={}", sessionId, sessionReport.estimatedLevel()); - + return ResponseGenerator.ok("세션이 완료되었습니다.", sessionReport); } - + // ==================== 유틸리티 ==================== - + /** * 질문 음성 URL 생성 (Polly + S3 캐싱) */ @@ -501,27 +572,27 @@ private String generateQuestionAudioUrl(OPIcQuestion question) { return null; } } - + /** * JWT 토큰에서 userId 추출 */ private String extractUserId(APIGatewayProxyRequestEvent event) { String authHeader = event.getHeaders().get("Authorization"); - + if (authHeader == null || authHeader.isEmpty()) { authHeader = event.getHeaders().get("authorization"); } - + return JwtUtil.extractUserId(authHeader) .orElseThrow(() -> new RuntimeException("인증 정보를 찾을 수 없습니다.")); } - + private static class InstantTypeAdapter implements JsonSerializer, JsonDeserializer { @Override public JsonElement serialize(Instant src, Type typeOfSrc, JsonSerializationContext context) { return new JsonPrimitive(src.toString()); } - + @Override public Instant deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { diff --git a/ServerlessFunction/template.yaml b/ServerlessFunction/template.yaml index 7b0e54bb..1e26aec5 100644 --- a/ServerlessFunction/template.yaml +++ b/ServerlessFunction/template.yaml @@ -1512,6 +1512,16 @@ Resources: Description: Daily word learning stats aggregation Enabled: true + ############################################# + # OPIc SNS Topics + ############################################# + + AnswerProcessTopic: + Type: AWS::SNS::Topic + Properties: + TopicName: !Sub "${AWS::StackName}-opic-answer-process" + DisplayName: "OPIc Answer Processing Topic" + ############################################# # OPIc Lambda Functions ############################################# @@ -1523,7 +1533,7 @@ Resources: CodeUri: . Handler: com.mzc.secondproject.serverless.domain.opic.handler.OPIcSessionHandler::handleRequest Description: Handle OPIc speaking practice sessions - Timeout: 180 + Timeout: 30 MemorySize: 1024 SnapStart: ApplyOn: PublishedVersions @@ -1531,11 +1541,14 @@ Resources: Variables: TRANSCRIBE_API_KEY: "/opic/transcribe-proxy-api-key" NOTIFICATION_TOPIC_ARN: !Ref NotificationTopic + ANSWER_PROCESS_TOPIC_ARN: !Ref AnswerProcessTopic Policies: - DynamoDBCrudPolicy: TableName: !Ref OPIcTable - S3CrudPolicy: BucketName: !Sub "${AWS::StackName}" + - SNSPublishMessagePolicy: + TopicName: !GetAtt AnswerProcessTopic.TopicName - Statement: - Effect: Allow Action: @@ -1608,6 +1621,15 @@ Resources: Method: POST Auth: Authorizer: CognitoAuthV2 + # 답변 상태 조회 (폴링용) ← 새로 추가! + GetAnswerStatus: + Type: Api + Properties: + RestApiId: !Ref MainApi + Path: /opic/sessions/{sessionId}/answers/{questionIndex}/status + Method: GET + Auth: + Authorizer: CognitoAuthV2 # 세션 완료 CompleteSession: Type: Api @@ -1627,6 +1649,43 @@ Resources: Auth: Authorizer: CognitoAuthV2 + # 비동기 답변 처리 Lambda + OPIcAnswerProcessFunction: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Sub "${AWS::StackName}-opic-answer-processor" + CodeUri: . + Handler: com.mzc.secondproject.serverless.domain.opic.handler.AnswerProcessHandler::handleRequest + Description: Process OPIc answers asynchronously (STT + AI Feedback) + Timeout: 600 + MemorySize: 1024 + SnapStart: + ApplyOn: PublishedVersions + Environment: + Variables: + TRANSCRIBE_API_KEY: "/opic/transcribe-proxy-api-key" + Policies: + - DynamoDBCrudPolicy: + TableName: !Ref OPIcTable + - S3ReadPolicy: + BucketName: !Sub "${AWS::StackName}" + - Statement: + - Effect: Allow + Action: + - bedrock:InvokeModel + - bedrock:InvokeModelWithResponseStream + Resource: "*" + - Statement: + - Effect: Allow + Action: + - ssm:GetParameter + Resource: !Sub "arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/opic/*" + Events: + SNSTrigger: + Type: SNS + Properties: + Topic: !Ref AnswerProcessTopic + ############################################# # Speaking Lambda Functions ############################################# From d7ae47ed4bb549a1ebda8d5989c92e4df5b892c8 Mon Sep 17 00:00:00 2001 From: hyein Heo <128613248+hye-inA@users.noreply.github.com> Date: Tue, 27 Jan 2026 16:55:31 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor=20:=20=EB=A6=AC=ED=8F=AC=ED=8A=B8?= =?UTF-8?q?=20=EC=9D=B4=EB=A9=94=EC=9D=BC=20=EB=B0=9C=EC=86=A1=20=EB=B9=84?= =?UTF-8?q?=EB=8F=99=EA=B8=B0=ED=99=94=20=EB=A6=AC=ED=8C=A9=ED=86=A0?= =?UTF-8?q?=EB=A7=81=20(#557)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feature : Speaking Table & Function template.yaml 파일에 추가 (#513) * fix: BadgeRepository 클라이언트 초기화 패턴 통일 - 개별 DynamoDbEnhancedClient 생성 대신 AwsClients.dynamoDbEnhanced() 싱글톤 사용 - 다른 Repository들과 동일한 패턴 적용 - 불필요한 import 제거 Closes #396 * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feat : Speaking 관련 template 람다 함수 및 테이블 추가 --------- Co-authored-by: DDING JOO Co-authored-by: Claude Opus 4.5 * feature : 말하기 연습 기능 polly 서비스 권한 추가 (#514) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feat : Speaking 관련 template 람다 함수 및 테이블 추가 * feat : 말하기 기능에 polly 서비스 권한 추가 --------- Co-authored-by: DDING JOO Co-authored-by: Claude Opus 4.5 * feature : transcribe API KEY 추가 (#516) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage Co-Authored-By: Claude Opus 4.5 * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments Co-Authored-By: Claude Opus 4.5 * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility Co-Authored-By: Claude Opus 4.5 * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL Co-Authored-By: Claude Opus 4.5 * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests Co-Authored-By: Claude Opus 4.5 * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records Co-Authored-By: Claude Opus 4.5 * feat : Speaking 관련 template 람다 함수 및 테이블 추가 * feat : 말하기 기능에 polly 서비스 권한 추가 * feat : transcribe API KEY 추가 --------- Co-authored-by: DDING JOO Co-authored-by: Claude Opus 4.5 * feat: 채팅 슬래시 명령어 시스템 고도화 - 게임 관련 명령어 제거 (/start, /stop, /score, /skip, /hint) - 기본 명령어 추가: /help, /members, /leave, /clear - 재미 명령어 추가: /dice, /coin, /random - 투표 시스템 구현: /poll, /vote, /endpoll - Poll 모델 및 PollRepository 추가 - MessageType에 POLL_CREATE, POLL_VOTE, POLL_END 추가 Closes #518, #519, #520 * feature : Test 브랜치 코드 Prod 브랜치 병합 (#529) * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add real-time notification system with SNS/SQS and Lambda Streaming - Add NotificationTopic and NotificationQueue SNS/SQS infrastructure - Implement NotificationPublisher service for publishing notifications - Create NotificationStreamHandler for SSE via Lambda Function URL - Integrate badge earned notifications in BadgeService - Add daily study completion notifications in DailyStudyCommandService - Add test/quiz result notifications in TestCommandService and NewsQuizService - Add SQS client to AwsClients and JsonUtil helper methods Closes #500, #501, #502, #505, #506 * feat: add streak reminder and game end notifications * refactor: extract config classes and apply DRY principle to news/notification domains * test: add Spock specs for notification and news domain configs * feature : Speaking Table & Function template.yaml 파일에 추가 (#513) * fix: BadgeRepository 클라이언트 초기화 패턴 통일 - 개별 DynamoDbEnhancedClient 생성 대신 AwsClients.dynamoDbEnhanced() 싱글톤 사용 - 다른 Repository들과 동일한 패턴 적용 - 불필요한 import 제거 Closes #396 * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * Release: 캐치마인드 게임 분리, AI 회화 연습, CI/CD 파이프라인 (#469) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 ## 변경 사항 ### GSI1SK 포맷 변경 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} ### 지원 쿼리 패턴 - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") ### 파일 수정 - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) ### 마이그레이션 - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes --------- Co-authored-by: hyein Heo <128613248+hye-inA@users.noreply.github.com> * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * feat(news): 뉴스 도메인 기반 구조 구축 (#385) - NewsCategory, QuizType enum 추가 - NewsKey 상수 클래스 추가 - NewsErrorCode 예외 클래스 추가 - NewsArticle, KeywordInfo, QuizQuestion 모델 추가 - NewsArticleRepository CRUD 구현 - NewsTable DynamoDB 테이블 정의 - CORS GatewayResponses 설정 추가 * feat(news): 뉴스 수집 파이프라인 구현 (#386) - NewsApiClient: NewsAPI 연동 서비스 - RssFeedParser: RSS 피드 파싱 (BBC, VOA, NPR) - NewsDuplicateChecker: URL 기반 중복 필터링 - NewsCollectorService: 수집 오케스트레이션 - NewsCollectionHandler: Lambda 핸들러 - EventBridge 스케줄러: 매일 18시 KST 실행 * refactor(news): NewsAPI 제거, RSS만 사용 - NewsApiClient 삭제 - SSM Parameter 의존성 제거 - RSS 소스당 7개씩 수집 (BBC, VOA, NPR = 약 21개/일) * feat(news): AI 뉴스 분석 시스템 구현 (#387) - NewsAnalysisService: AI 분석 통합 서비스 - Bedrock: CEFR 난이도 분석 (A1~C2) - Bedrock: 3줄 요약 + 퀴즈 3문제 생성 - Comprehend: 핵심 키워드 추출 - NewsCollectorService: 수집 시 자동 분석 연동 - GSI1/GSI2 키 자동 설정 (레벨별, 카테고리별 조회) * feat(news): 뉴스 학습 API 구현 (#388) - NewsQueryService: 뉴스 조회 서비스 - NewsHandler: API 핸들러 - GET /news - 목록 조회 (level, category 필터) - GET /news/today - 오늘의 뉴스 - GET /news/recommended - 내 레벨 맞춤 추천 - GET /news/{articleId} - 상세 조회 (조회수 증가) - template.yaml: NewsFunction Lambda 추가 * feat(news): 뉴스 학습 부가 기능 구현 (#389) - 읽기 완료 기록 API (POST /news/{articleId}/read) - 북마크 토글 API (POST /news/{articleId}/bookmark) - 북마크 목록 조회 API (GET /news/bookmarks) - 학습 통계 조회 API (GET /news/stats) - TTS 오디오 URL 조회 API (GET /news/{articleId}/audio) - UserNewsRecord 모델 추가 - UserNewsRepository 추가 - NewsLearningService 추가 * feat(news): 복합 퀴즈 시스템 구현 (#471) - 퀴즈 조회 API (GET /news/{articleId}/quiz) - 퀴즈 제출 API (POST /news/{articleId}/quiz) - 퀴즈 기록 조회 API (GET /news/quiz/history) - NewsQuizResult 모델 추가 - QuizAnswerResult 모델 추가 - NewsQuizRepository 추가 - NewsQuizService 추가 * feat(news): 단어 수집 & Vocabulary 연동 구현 (#472) - 단어 수집 API (POST /news/{articleId}/words) - 수집 단어 목록 API (GET /news/words) - 단어 상세 조회 API (GET /news/{articleId}/words/{word}) - 단어 삭제 API (DELETE /news/{articleId}/words/{word}) - Vocabulary 연동 API (POST /news/words/{word}/sync) - NewsWordCollect 모델 추가 - NewsWordRepository 추가 - NewsWordService 추가 * feat: add multi-environment deployment support (dev/test/prod) * fix: update buildspec.yml to deploy prod environment with parameter overrides * refactor : AI 말하기 Websocket 구현 -> REST API 구현으로 리팩토링 (#490) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: revert buildspec.yml to build-only for CloudFormation deploy stage * fix: update all API Gateway StageName to use Environment parameter * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: correct VocabularyTable and ContentBucket references in NewsFunction * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * fix: add stack name prefix to GameScheduleGroup and daily-stats schedule to avoid conflicts * feat: add support for existing Cognito User Pool reuse across environments * fix: add conditional Cognito ARN reference in API Gateway Authorizer * fix: remove Cognito resources completely, use existing Cognito only * fix: remove Cognito resources completely, use existing Cognito only * feat : speaking rest API 람다 함수 추가 * feat: add S3 bucket resource and fix environment-specific endpoints - Add ContentBucket S3 resource for content storage - Replace hardcoded /dev with ${Environment} in all WebSocket endpoints - Update Output URLs to use dynamic environment stage * fix: add stack name prefix to news-collection schedule name Prevent EventBridge rule name conflicts across environments * fix: add X-Requested-With and Accept headers to CORS config Enable additional headers for CloudFront CORS compatibility * fix: use environment variable for S3 bucket URLs Replace hardcoded bucket name with BUCKET_NAME env var for multi-env support: - PreSignUpHandler: dynamic default profile URL - PostConfirmationHandler: dynamic default profile URL - UserService: dynamic default profile URL - BadgeType: dynamic badge image base URL * fix: disable authorizer for CORS preflight requests Add AddDefaultAuthorizerToCorsPreflight: false to prevent Cognito Authorizer from blocking OPTIONS requests * feat : speaking REST API 람다 함수 추가 (#491) * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 포함 Closes #428 * feat: GameSessionRepository 구현 - 기본 CRUD (save, findById, delete) - roomId로 활성/전체 게임 세션 조회 - 상태, 라운드, 점수 업데이트 메서드 - 정답자 추가, 힌트 사용, 게임 종료 처리 Closes #429 * refactor: ChatRoom에서 게임 필드 분리 - 게임 관련 필드 제거 (gameStatus, currentRound 등) - activeGameSessionId 필드 추가 - 게임 상태는 GameSession으로 분리됨 Note: 의존 코드 수정은 #431에서 진행 Closes #430 * refactor: GameSession 기반으로 전체 게임 로직 리팩토링 - GameService: ChatRoom 대신 GameSession 사용 - GameStatsService: GameSession 매개변수로 변경 - CommandService: GameSession 기반 점수 조회 - GameHandler: GameSession 기반 REST API - WebSocketMessageHandler: GameSession 기반 브로드캐스트 - GameStatusResponse, ScoreboardResponse: GameSession 매개변수 Closes #431 * feat: GameSessionHandler Lambda 및 게임 세션 API 구현 - POST /rooms/{roomId}/games - 게임 세션 생성 - GET /games/{gameSessionId} - 게임 상태 조회 (재접속용) - POST /games/{gameSessionId}/start - 게임 시작 - POST /games/{gameSessionId}/stop - 게임 종료 모든 응답에 serverTime 포함 (타이머 동기화) 출제자에게만 currentWord 포함 Closes #432, #433 * feat: 게임 시작 7분 후 자동 종료 기능 구현 - GameConfig에 gameTimeLimit() 메서드 추가 (기본값: 420초) - GameSchedulerClient 유틸리티 클래스 생성 (EventBridge Scheduler 연동) - GameService에 스케줄 생성/취소 로직 추가 - GameAutoCloseHandler Lambda 함수 생성 - template.yaml에 Lambda, IAM Role, Schedule Group 추가 Closes #417 * fix : 메모리 증가 및 Lambda 응답 제한 시간 Cognito 트리거 제한시간과 동일하게 수정 (#439) * feat: 캐치마인드 게임 방 분리 기능 구현 (#455) - Room 타입 분리 (CHAT/GAME) - RoomType, RoomStatus enum 추가 - ChatRoom 모델에 type, gameType, gameSettings, status, hostId 필드 추가 - GameSettings 모델 추가 - 방 생성/조회 API 수정 - CreateRoomRequest에 type, gameType, gameSettings 필드 추가 - 방 목록 조회 시 type, gameType, status 필터 지원 - 게임 시작 조건 검증 - GAME 타입 방에서만 게임 시작 가능 (GAME_007 에러) - 게임 재시작 API 구현 (#452) - POST /rooms/{roomId}/game/restart 엔드포인트 추가 - 방장만 재시작 가능 (GAME_009 에러) - 게임 진행 중 재시작 불가 (GAME_008 에러) - 방장 변경 로직 구현 (#453) - 방장 퇴장 시 다음 멤버에게 자동 이전 - 모든 멤버 퇴장 시 방 자동 삭제 - WebSocket 메시지 타입 추가 (#454) - ROOM_STATUS_CHANGE, HOST_CHANGE 메시지 타입 추가 - WebSocketMessageHelper에 빌더 메서드 추가 - 테스트 추가 - RoomType, RoomStatus enum 테스트 - GameSettings 모델 테스트 - ChattingErrorCode 테스트 업데이트 Related: #440, #441, #442, #443, #444, #445, #446 Closes: #447, #448, #449, #450, #451, #452, #453, #454 * feat: 참가자 닉네임 및 방장 변경 WebSocket 알림 구현 (#456) - RoomParticipant DTO 추가 (userId, nickname, isHost) - ChatRoomQueryService에 닉네임 조회 메서드 추가 - getParticipantsWithNicknames(): 참가자 목록 + 닉네임 - getHostNickname(): 방장 닉네임 조회 - ChatRoomHandler.getRoom() 응답에 participants, hostNickname 추가 - ChatRoomCommandService.leaveRoom()에서 방장 변경 시 WebSocket 브로드캐스트 Related: #440 * fix: ChatRoomFunction에 UserTable DynamoDB 권한 추가 - 참가자/방장 닉네임 조회를 위한 UserTable 읽기 권한 추가 - DynamoDBReadPolicy로 UserTable 접근 허용 Fixes #457 * fix: GameSettings에 @DynamoDbBean 어노테이션 추가 - DynamoDB Enhanced Client가 중첩 객체를 직렬화/역직렬화할 수 있도록 수정 - ChatRoom 저장/조회 시 GameSettings 변환 오류 해결 Fixes #457 * fix: ChatRoomFunction에 WEBSOCKET_ENDPOINT 환경변수 및 권한 추가 - leaveRoom에서 WebSocketBroadcaster 사용을 위한 환경변수 추가 - execute-api:ManageConnections 권한 추가 * fix: WebSocket Lambda 함수들에 WEBSOCKET_ENDPOINT 환경변수 추가 - WebSocketConnectFunction에 WEBSOCKET_ENDPOINT 추가 - WebSocketDisconnectFunction에 WEBSOCKET_ENDPOINT 추가 - execute-api:ManageConnections 권한 추가 * fix: Grammar WebSocket Lambda 환경 변수 및 권한 추가 - GrammarStreamingConnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - GrammarStreamingDisconnectFunction에 WEBSOCKET_ENDPOINT 환경 변수 추가 - 두 함수에 execute-api:ManageConnections 권한 추가 * feat: GSI1SK 확장성 있는 재설계 및 DB 레벨 필터링 - 기존: {level}#{createdAt} - 신규: {type}#{gameType}#{status}#{level}#{createdAt} - 전체 방: GSI1PK = "ROOMS" - 게임방만: begins_with(GSI1SK, "GAME#") - 캐치마인드만: begins_with(GSI1SK, "GAME#CATCHMIND#") - 대기중 캐치마인드: begins_with(GSI1SK, "GAME#CATCHMIND#WAITING#") - ChatRoomCommandService.java: 방 생성 시 새 GSI1SK 포맷 적용 - ChatRoomRepository.java: findByFilters() 메서드 추가, updateStatus() 메서드 추가 - ChatRoomQueryService.java: 메모리 필터링 제거, DB 레벨 필터링으로 변경 - GameService.java: 게임 시작/종료 시 방 상태 업데이트 (GSI1SK 포함) - scripts/migrate-gsi1sk.sh: 기존 데이터 마이그레이션 스크립트 - 37개 기존 방 마이그레이션 완료 * fix: increase stats query limit to 100 days - Adjust maximum allowable limit for recent stats query from 30 to 100 days to support extended data range responses. * feat: improve game round and connection management logic - Added handling for game round timeout (`ROUND_TIMEOUT`) in WebSocketMessageHandler. - Enhanced game start broadcast to include `currentWord` for the drawer only. - Updated ConnectionRepository to remove duplicate user connections in the same room. - Added `currentWordEnglish` to GameSession for better answer verification. - Normalized ChatRoom levels to match database storage format. - Updated template.yaml to include DynamoDBReadPolicy for VocabTable. * refactor: 코드 정리 및 미사용 클래스 제거 (#459) * refactor: remove unused WebSocketResponseUtil * refactor: add AutoCloseable to WebSocketBroadcaster * refactor: remove unused TestService * refactor: remove unused WordService * refactor: remove unused DailyStudyService * refactor: remove unused UserWordService * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * style: remove p tag from javadoc * fix: resolve N+1 query in StatsService * refactor(all): DI 패턴 및 전략 패턴 적용 (#461) - Repository, Service, Handler에 DI 생성자 추가 (테스트 용이성) - BadgeService에 Strategy 패턴 적용 (뱃지 조건 검증 로직 분리) * refactor: relocate and restructure seed data files - Moved `question-homes.json` and `words.json` from subdirectories to `seed` folder. - Updated file paths for better organization and clarity. * chore: seed 데이터 폴더 구조 정리 * feat: add CI/CD pipeline configuration for CodePipeline * fix: add SNS topic policy and DependsOn for notification rule * fix: correct paths in buildspec.yml for CodeBuild * fix: remove hardcoded JAVA_HOME, use runtime default * fix: add gradle wrapper for CI/CD build * fix: use single line sam package command with hardcoded bucket * fix: use existing stack name group2-englishstudy-chatting * fix: add missing WEBSOCKET_ENDPOINT env var to WebSocket connect functions * docs: update FRONTEND-API-GUIDE with new RoomType/RoomStatus structure * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: update WebSocketDisconnectHandler to use GameSession model - Remove references to deleted ChatRoom game fields - Use GameSessionRepository to finish active game sessions - Use ChatRoomRepository.updateStatus() for room state management * perf: optimize CI/CD build time - Add pip cache for SAM CLI dependencies - Enable Gradle parallel builds and build cache - Add SAM build cache (.aws-sam) - Use sam build --parallel --cached - Skip SAM CLI install if already cached - Remove unnecessary 'clean' to leverage cache * feat: add custom CodeBuild Docker image with pre-installed tools - Dockerfile with Java 21 + SAM CLI + Gradle pre-installed - build-and-push.sh script for ECR deployment - Updated buildspec.yml for custom image (removes SAM CLI install) - Expected build time reduction: ~30-40 seconds * feature : AI 영어 회화 연습 기능 (#468) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix: remove typo in SpeakingConnectionRepository * fix : 오타 수정 * chore: trigger build test with custom Docker image * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * chore: remove unnecessary newlines and whitespace across WebSocket handlers and related classes * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * fix: add CORS headers to API Gateway error responses (#479) API Gateway의 인증 실패 등 에러 응답에 CORS 헤더가 누락되어 CloudFront를 통한 프론트엔드 요청이 차단되는 문제 수정 - UNAUTHORIZED (401) 응답에 CORS 헤더 추가 - ACCESS_DENIED (403) 응답에 CORS 헤더 추가 - DEFAULT_4XX/5XX 응답에 CORS 헤더 추가 - EXPIRED_TOKEN 응답에 CORS 헤더 추가 * feat : speaking rest API 람다 함수 추가 --------- Co-authored-by: ddingjoo * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feature : test 벡엔드 서버에 AI 말하기 연습 기능 배포 (#492) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 --------- Co-authored-by: DDING JOO * feat : handleChat 메서드 JsonNull 체크 푸가 * feature : handleChat 메서드 JsonNull 체크 추가 (#493) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 --------- Co-authored-by: DDING JOO * feat(news): 뉴스 학습 배지 시스템 구현 (#473) - 14개 뉴스 관련 배지 추가 (읽기, 퀴즈, 단어수집, 연속학습, 마스터) - UserStats에 뉴스 통계 필드 추가 - 6개 뉴스 배지 Strategy 클래스 생성 - 뉴스 읽기/퀴즈/단어수집 시 통계 업데이트 및 배지 체크 연동 * fix: add PATCH method to CORS AllowMethods * test: BadgeType 개수 테스트 수정 (15 -> 29) * fix: CORS PATCH 메서드 추가 * docs: 뉴스 기능 프론트엔드 연동 가이드 작성 * fix: NewsCollectionFunction에 Bedrock, Comprehend 권한 추가 * fix: add null check for collectWord request body - Add INVALID_REQUEST error code to NewsErrorCode - Check body and word field before accessing in collectWord() - Prevents NullPointerException when request body is malformed * feat: enhance stats API and bookmark response for frontend - Add DAILY stats update for news read/quiz/word collection - Add /stats/dashboard endpoint with frontend-requested format - today: wordsLearned, newsRead, quizzesTaken, wordsTotal - overall: totalWordsLearned, totalNewsRead, averageAccuracy, streaks - weeklyProgress: last 7 days with date/wordsLearned/newsRead - Add news-related fields to all stats API responses - Fix bookmark API to include full article details (title, summary, etc.) * feat: add category classification to news AI analysis - Add category field to AnalysisResult record - Update Bedrock prompt to classify articles into categories (WORLD, POLITICS, BUSINESS, TECH, SCIENCE, HEALTH, SPORTS, ENTERTAINMENT, LIFESTYLE) - Parse and set category from AI response - Set GSI2 (CATEGORY#) index when category is available * fix: add /stats/dashboard endpoint to template.yaml * fix: filter by ARTICLE# prefix in findById to avoid returning UserNewsRecord * docs: add News API troubleshooting guide * feat: add Cognito authorizer to News API and enhance keyword extraction - Set CognitoAuthorizer for all News API endpoints in template.yaml - Update Bedrock AI to extract keywords with meanings and examples - Add fallback to Comprehend for keyword extraction when Bedrock fails - Modify KeywordInfo model to include example field - Adjust AI prompt to include keyword extraction with examples - Update AnalysisResult to store keywords and parse them from AI response * Revert "Merge branch 'test' into prod" This reverts commit c1a958eac6799d5838a76e4078ae304bcdb62278, reversing changes made to a6662e0cfc46c6e12f20a89f0df285ff282160bc. * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 * fix : sessionId NullPointerException 에러 수정 (#496) * feat : WebSocket Connect, Disconnect 핸들러 & SpeakingConnecion 모델 구현 * feat : WebSocket 메시지 처리 handler, service 구현 * feat : WebSocket 연결 정보 Repository 구현 * fix : 오타 수정 * refactor : websocket -> rest api 전환 * feat : speaking handler REST로 교체 * feat : speaking 관련 dto 생성 * refacotor : 기존 service 코드 로직 재사용 및 repository 리펙토링 * feat : speaking rest API 람다 함수 추가 * refactor : speaking service 재사용 * refactor : AI 영어 회화 연습 코드 리팩토링 * feat : handleChat 메서드 JsonNull 체크 푸가 * refactor : session_id가 null 체크 추가 * feat : template 환경변수 리펙토링 --------- Co-authored-by: DDING JOO * feat: enhance bookmark and reading status tracking for News API - Add bookmark and reading status to individual article responses - Include bookmark status in paginated news responses - Modify `KeywordInfo` to support Korean translations (`meaningKo`) - Update AI prompts to extract Korean meanings for keywords * feat: add category filtering to UserWord API with enhanced query logic - Introduce `category` filtering to `getUserWords` API - Update WordCategory enums to include "news" category - Apply category filter after enrichment with word info - Adjust query limits for bookmarked and incorrect words queries * feat: add default value for ExistingCognitoClientId in template.yaml - Set default to an empty string to ensure compatibility with templates using this parameter without explicitly specifying a value. * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: SpeakingHandler getStringOrNull 컴파일 에러 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정 * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * feat: add dashboard stats API and enhance news stats tracking - Introduce `/stats/dashboard` API for retrieving integrated user stats (today, overall, weekly progress, and level distribution) - Update `UserStats` model to include additional fields for news stats (newsRead, newsQuizCompleted, newsQuizPerfect, newsWordsCollected, etc.) - Add atomic updates to track news reading, quiz, and word stats in `UserStatsRepository` - Modify CloudFormation `template.yaml` to register the new `/stats/dashboard` endpoint * refactor: format code with consistent indentation and spacing - Apply consistent formatting to improve code readability across multiple files - Adjust indentation, spacing, and alignment in model classes, DTOs, and repository methods * fix: filter by ARTICLE# prefix in findById to avoid returning bookmark records * feat : Speaking 관련 template 람다 함수 및 테이블 추가 --------- Co-authored-by: DDING JOO * feature : 말하기 연습 기능 polly 서비스 권한 추가 (#514) * feat: EnvConfig 유틸리티 추가 및 환경 변수 검증 적용 환경 변수 미설정 시 명확한 에러 메시지를 제공하는 EnvConfig 유틸리티를 추가하고, 기존 System.getenv 호출을 EnvConfig.getRequired/getOrDefault로 대체함. - EnvConfig: getRequired, getOrDefault, getIntOrDefault, getLongOrDefault 메서드 제공 - Lambda Cold Start 시점에 환경 변수 누락을 조기 감지 - 기존 Config 클래스(WebSocketConfig, RoomTokenConfig) EnvConfig 사용으로 통일 Closes #403 * refactor: TestService submitTest 메서드 책임 분리 submitTest 메서드를 단일 책임 원칙에 맞게 리팩토링: - gradeAnswers(): 답안 채점 및 결과 집계 - isAnswerCorrect(): 단일 답안 정답 여부 판단 - buildResultItem(): 결과 항목 생성 - saveTestResult(): 테스트 결과 저장 - GradingResult record: 채점 결과 캡슐화 TestService와 TestCommandService 모두 동일하게 적용 Closes #404 * refactor: 하드코딩된 설정값 환경 변수로 외부화 각 도메인별 Config 클래스를 생성하여 하드코딩된 값들을 환경 변수로 설정 가능하게 변경. 기본값이 있어 환경 변수 미설정 시에도 기존 동작 유지. ## 새로 추가된 Config 클래스 - GrammarConfig: SESSION_TTL_DAYS, MAX_HISTORY_MESSAGES, MAX_TOKENS 등 - GameConfig: TOTAL_ROUNDS, ROUND_TIME_LIMIT, QUICK_GUESS_THRESHOLD_MS - VocabularyConfig: NEW_WORDS_COUNT, REVIEW_WORDS_COUNT, 상태 전이 임계값 등 ## 지원하는 환경 변수 - GRAMMAR_SESSION_TTL_DAYS, GRAMMAR_MAX_HISTORY_MESSAGES, GRAMMAR_MAX_TOKENS - GAME_TOTAL_ROUNDS, GAME_ROUND_TIME_LIMIT, GAME_QUICK_GUESS_THRESHOLD_MS - VOCAB_NEW_WORDS_COUNT, VOCAB_REVIEW_WORDS_COUNT - VOCAB_TRANSITION_TO_REVIEWING, VOCAB_TRANSITION_TO_MASTERED Closes #406 * test: StudyLevel enum 단위 테스트 추가 * test: Difficulty enum 단위 테스트 추가 * test: StudyConfig 단위 테스트 추가 * test: EnvConfig 단위 테스트 추가 * test: PaginatedResult 단위 테스트 추가 * test: JsonUtil 단위 테스트 추가 * test: CursorUtil 단위 테스트 추가 * test: CommonErrorCode 단위 테스트 추가 * test: CommonException 단위 테스트 추가 * test: BadgeType enum 단위 테스트 추가 * test: BadgeKey 상수 단위 테스트 추가 * test: WordStatus enum 단위 테스트 추가 * test: TestType enum 단위 테스트 추가 * test: VocabularyConfig 단위 테스트 추가 * test: VocabKey 상수 단위 테스트 추가 * test: VocabularyErrorCode 단위 테스트 추가 * test: VocabularyException 단위 테스트 추가 * test: SpacedRepetitionContext 단위 테스트 추가 * test: GrammarLevel enum 단위 테스트 추가 * test: GrammarConfig 단위 테스트 추가 * test: GrammarErrorCode 단위 테스트 추가 * test: GrammarException 단위 테스트 추가 * test: GameStatus enum 단위 테스트 추가 * test: GameConfig 단위 테스트 추가 * test: ChattingErrorCode 단위 테스트 추가 * test: ChattingException 단위 테스트 추가 * fix: OPIc FeedbackResponse.java 문법 오류 수정 * style: AwsClients 코드 포맷팅 * style: EnvConfig 코드 포맷팅 * style: RoomTokenConfig 코드 포맷팅 * style: WebSocketConfig 코드 포맷팅 * style: JsonUtil 코드 포맷팅 * style: GameConfig 코드 포맷팅 * style: GrammarConfig 코드 포맷팅 * style: GrammarKey 코드 포맷팅 * style: GrammarErrorCode 코드 포맷팅 * style: GrammarException 코드 포맷팅 * style: BedrockGrammarCheckFactory 코드 포맷팅 * style: GrammarConversationService 코드 포맷팅 * style: FeedbackResponse 코드 포맷팅 * style: SessionReportResponse 코드 포맷팅 * style: SpeakingError 코드 포맷팅 * style: SpeakingErrorType 코드 포맷팅 * style: OPIcException 코드 포맷팅 * style: OPIcAnswer 코드 포맷팅 * style: OPIcQuestion 코드 포맷팅 * style: OPIcSession 코드 포맷팅 * style: OPIcRepository 코드 포맷팅 * style: FeedbackService 코드 포맷팅 * style: TranscribeProxyService 코드 포맷팅 * style: VocabularyConfig 코드 포맷팅 * style: DailyStudyCommandService 코드 포맷팅 * style: TestCommandService 코드 포맷팅 * style: TestService 코드 포맷팅 * style: CommonErrorCodeSpec 코드 포맷팅 * style: JsonUtilSpec 코드 포맷팅 * style: BadgeTypeSpec 코드 포맷팅 * style: ChattingErrorCodeSpec 코드 포맷팅 * style: GrammarLevelSpec 코드 포맷팅 * style: GrammarErrorCodeSpec 코드 포맷팅 * style: VocabularyErrorCodeSpec 코드 포맷팅 * feature : OPIc 세션관리 + 답변 처리 파이프라인 구현 (#413) * feat : OPIc 질문 & 세션 관련 dto 생성 * refactor : @DynamoDbBean 주석 추가 * feat : 주제 + 소주제 + 레벨로 오픽 질문 조회 추가 * feat : OPIc 세션, 질문, 답변 종합 handler 구현 * feat : 오픽 주제, 소주제별 seed 데이터 추가 * refactor : Transcribe API KEY 환경변수명 수정 * refactor : Bedrock에 사용하는 클로드 모델 변경 * refactor : S3 Key 대신 Proxy에서 요청하는 Base64 값으로 변환 * feat: GAME_START, ROUND_END 메시지에 serverTime 추가 - broadcastGameStart(): serverTime, roundDuration 필드 추가 - broadcastRoundEnd(): serverTime, roundStartTime, roundDuration 필드 추가 - GameService.endRound(): data에 roundStartTime, roundDuration 포함 - 타이머 동기화 버그 수정을 위한 서버 시간 제공 * feat: WebSocketMessageHelper 유틸리티 클래스 추가 - domain 필드 포함 메시지 생성 헬퍼 - DOMAIN_CHAT, DOMAIN_GAME 상수 정의 - buildChatMessage(), buildGameMessage() 메서드 * feat: 모든 WebSocket 메시지에 domain 필드 추가 - ScoreUpdateMessage에 domain 필드 추가 - broadcastGameStart에 domain:"game" 추가 - broadcastRoundEnd에 domain:"game" 추가 - broadcastCorrectAnswerMessage에 domain:"game" 추가 - handleCommandResult 시스템 메시지에 domain:"game" 추가 - handleRegularMessage 채팅 메시지에 domain:"chat" 추가 Closes #426, #427 * feat: GameSession 모델 클래스 생성 - DynamoDB Enhanced Client 어노테이션 적용 - GSI1: roomId로 활성 게임 세션 조회 가능 - 게임 상태 관리용 헬퍼 메서드 … * feat: implement word chain (끝말잇기) game with dictionary API integration - Add WordChainSession model with time limit, scoring, player management - Add WordChainService with game logic (start, submit, timeout, stop) - Add DictionaryService for word validation via Free Dictionary API - Add WordChainHandler REST API endpoints (/wordchain/start, submit, etc.) - Add WordChainFunction to SAM template - Add WORDCHAIN_* message types for WebSocket broadcasts - Fix command result domain (use chat domain for chat commands) - Add unit tests for WordChainSession and DictionaryService Closes #524, #525, #526, #527, #528 * fix: update ChattingErrorCodeSpec to include new error codes * fix: add UserTable read permission to WebSocket Lambda WebSocket Lambda needs DynamoDBReadPolicy for UserTable to look up user nicknames for chat commands (/member, /dice, /coin, /hint, etc.) * fix: add Bedrock permission to NewsCollectionFunction NewsCollectionFunction needs bedrock:InvokeModel permission to analyze news difficulty using Claude. * fix: fallback to yesterday's news when today's news is empty GET /news now returns yesterday's articles if no articles exist for today. This prevents empty results before the daily 18:00 KST news collection runs. * feat : SES 클라이언트 의존성 추가 * feat : OPIc 람다에 SES 권한 추가 * feat : OPIc 세션 리포트 이메일 발송 서비스 추가 * refactor : 오픽 답변 비동기 처리 * refactor : 이메일 발송 비동기로 전환 코드 리팩토링 * feat : 이메일 발송 전용 비동기 Lambda 추가 * feat : 이메일 발송 전용 비동기 Lambda 추가 * refactor : 이메일 발송 비동기로 전환 코드 리팩토링 * feat : 이메일 발송 전용 비동기 Lambda 추가 --------- Co-authored-by: ddingjoo Co-authored-by: Claude Opus 4.5 --- .../opic/handler/EmailAsyncHandler.java | 25 ++++++++++++++++ .../opic/handler/OPIcSessionHandler.java | 29 +++++++++++++++++-- ServerlessFunction/template.yaml | 21 +++++++++++++- 3 files changed, 71 insertions(+), 4 deletions(-) create mode 100644 ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/EmailAsyncHandler.java diff --git a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/EmailAsyncHandler.java b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/EmailAsyncHandler.java new file mode 100644 index 00000000..59a75133 --- /dev/null +++ b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/EmailAsyncHandler.java @@ -0,0 +1,25 @@ +package com.mzc.secondproject.serverless.domain.opic.handler; + +import com.amazonaws.services.lambda.runtime.Context; +import com.amazonaws.services.lambda.runtime.RequestHandler; +import com.amazonaws.services.lambda.runtime.events.SNSEvent; +import com.google.gson.Gson; +import com.mzc.secondproject.serverless.domain.opic.service.EmailService; + +public class EmailAsyncHandler implements RequestHandler { + private final EmailService emailService = new EmailService(); + private final Gson gson = new Gson(); + + @Override + public Void handleRequest(SNSEvent event, Context context) { + for (SNSEvent.SNSRecord record : event.getRecords()) { + String messageBody = record.getSNS().getMessage(); + processMessage(messageBody); + } + return null; + } + private void processMessage(String body) { + // 메시지 파싱 및 타입 확인 (OPIC_REPORT_EMAIL) + // emailService.sendOPIcReportEmail 호출 + } +} \ No newline at end of file diff --git a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java index c79576d2..8f9c13cb 100644 --- a/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java +++ b/ServerlessFunction/src/main/java/com/mzc/secondproject/serverless/domain/opic/handler/OPIcSessionHandler.java @@ -15,6 +15,7 @@ import com.mzc.secondproject.serverless.domain.opic.dto.response.CreateSessionResponse; import com.mzc.secondproject.serverless.domain.opic.dto.response.FeedbackResponse; import com.mzc.secondproject.serverless.domain.opic.dto.response.QuestionResponse; +import com.mzc.secondproject.serverless.domain.opic.dto.response.SessionReportResponse; import com.mzc.secondproject.serverless.domain.opic.model.OPIcAnswer; import com.mzc.secondproject.serverless.domain.opic.model.OPIcQuestion; import com.mzc.secondproject.serverless.domain.opic.model.OPIcSession; @@ -533,8 +534,8 @@ private APIGatewayProxyResponseEvent completeSession(APIGatewayProxyRequestEvent String userName = CognitoUtil.extractNickname(event).orElse("학습자"); if (userEmail != null && !userEmail.isEmpty()) { - emailService.sendOPIcReportEmail(userEmail, userName, sessionReport); - logger.info("리포트 이메일 발송 완료: to={}", userEmail); + publishEmailToSNS(userEmail, userName, sessionReport); + logger.info("이메일 발송 SNS 요청 발행: to={}", userEmail); } } catch (Exception e) { // 이메일 실패해도 세션 완료는 성공 처리 @@ -554,7 +555,29 @@ private APIGatewayProxyResponseEvent completeSession(APIGatewayProxyRequestEvent return ResponseGenerator.ok("세션이 완료되었습니다.", sessionReport); } - // ==================== 유틸리티 ==================== + /** + * 이메일 발송용 SNS 메시지 발행 + */ + private void publishEmailToSNS(String email, String userName, SessionReportResponse report) { + try { + String topicArn = System.getenv("NOTIFICATION_TOPIC_ARN"); + + Map message = new HashMap<>(); + message.put("type", "OPIC_REPORT_EMAIL"); + message.put("recipientEmail", email); + message.put("userName", userName); + message.put("report", report); // 세션 리포트 객체 전달 + + AwsClients.sns().publish(PublishRequest.builder() + .topicArn(topicArn) + .message(gson.toJson(message)) + .build()); + } catch (Exception e) { + logger.error("이메일 SNS 발행 실패", e); + } + } + + // ==================== 유틸리티 ====================Z /** * 질문 음성 URL 생성 (Polly + S3 캐싱) diff --git a/ServerlessFunction/template.yaml b/ServerlessFunction/template.yaml index 3ed8f0dc..5680182c 100644 --- a/ServerlessFunction/template.yaml +++ b/ServerlessFunction/template.yaml @@ -1622,7 +1622,7 @@ Resources: Method: POST Auth: Authorizer: CognitoAuthV2 - # 답변 상태 조회 (폴링용) ← 새로 추가! + # 답변 상태 조회 (폴링용) GetAnswerStatus: Type: Api Properties: @@ -1687,6 +1687,25 @@ Resources: Properties: Topic: !Ref AnswerProcessTopic + # 이메일 발송 전용 비동기 Lambda + OPIcEmailFunction: + Type: AWS::Serverless::Function + Properties: + FunctionName: !Sub "${AWS::StackName}-opic-email-handler" + Handler: com.mzc.secondproject.serverless.domain.opic.handler.EmailAsyncHandler::handleRequest + Events: + SNSEvent: + Type: SNS + Properties: + Topic: !Ref NotificationTopic + Policies: + - Statement: + - Effect: Allow + Action: + - ses:SendEmail + - ses:SendRawEmail + Resource: "*" + ############################################# # Speaking Lambda Functions #############################################