Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
0563433
fix: SpeakingHandler getStringOrNull 컴파일 에러 수정
DDINGJOO Jan 23, 2026
5f2bc1b
fix: Bedrock 키워드(meaningKo 포함)를 article에 저장하도록 수정
DDINGJOO Jan 23, 2026
f2b12a0
Merge prod into test: sync dashboard stats and news features
DDINGJOO Jan 23, 2026
fd2726b
Merge prod: fix findById ARTICLE# filter
DDINGJOO Jan 23, 2026
e5cec27
feat: add real-time notification system with SNS/SQS and Lambda Strea…
DDINGJOO Jan 23, 2026
6ae9936
feat: add streak reminder and game end notifications
DDINGJOO Jan 23, 2026
e4058ca
refactor: extract config classes and apply DRY principle to news/noti…
DDINGJOO Jan 23, 2026
c43e908
test: add Spock specs for notification and news domain configs
DDINGJOO Jan 23, 2026
2c5ec01
Merge pull request #510 from Language-Study-Prooject/feature/499/noti…
DDINGJOO Jan 23, 2026
239f47f
Merge pull request #511 from Language-Study-Prooject/develop
DDINGJOO Jan 23, 2026
126104c
feature : Speaking Table & Function template.yaml 파일에 추가 (#513)
hye-inA Jan 23, 2026
e5ff39a
feature : 말하기 연습 기능 polly 서비스 권한 추가 (#514)
hye-inA Jan 23, 2026
c01be8a
feature : transcribe API KEY 추가 (#516)
hye-inA Jan 23, 2026
1de4def
feat: 채팅 슬래시 명령어 시스템 고도화
DDINGJOO Jan 24, 2026
a375535
Merge pull request #521 from Language-Study-Prooject/feature/517-chat…
DDINGJOO Jan 24, 2026
377155c
Merge pull request #522 from Language-Study-Prooject/develop
DDINGJOO Jan 24, 2026
aac551a
feat: implement word chain (끝말잇기) game with dictionary API integration
DDINGJOO Jan 24, 2026
04e09b0
Merge pull request #530 from Language-Study-Prooject/feature/523-word…
DDINGJOO Jan 24, 2026
5a90f04
Merge pull request #531 from Language-Study-Prooject/develop
DDINGJOO Jan 24, 2026
161b305
fix: update ChattingErrorCodeSpec to include new error codes
DDINGJOO Jan 24, 2026
777bdb4
Merge pull request #532 from Language-Study-Prooject/develop
DDINGJOO Jan 24, 2026
18406b4
fix: add UserTable read permission to WebSocket Lambda
DDINGJOO Jan 24, 2026
2565c81
Merge pull request #533 from Language-Study-Prooject/develop
DDINGJOO Jan 24, 2026
c351b37
fix: add Bedrock permission to NewsCollectionFunction
DDINGJOO Jan 24, 2026
49e6c94
fix: fallback to yesterday's news when today's news is empty
DDINGJOO Jan 24, 2026
f1d5aa6
feature : 채팅 도메인 닉네임 조회용 메서드 추가 (#534)
hye-inA Jan 24, 2026
7cd2c69
feature : 채팅 메뉴에서 닉네임 조회 테스트 배포 (#535)
hye-inA Jan 24, 2026
309857b
fix: test 환경 Cognito User Pool을 prod와 동일하게 통일
DDINGJOO Jan 25, 2026
38d0cdb
Merge pull request #536 from Language-Study-Prooject/fix/unify-cognit…
DDINGJOO Jan 25, 2026
4341f8e
fix: add Cognito parameters to CI/CD buildspec and wordchain turnTime…
DDINGJOO Jan 25, 2026
ee3f9e4
Merge pull request #537 from Language-Study-Prooject/fix/unify-cognit…
DDINGJOO Jan 25, 2026
6032a70
Merge pull request #538 from Language-Study-Prooject/develop
DDINGJOO Jan 25, 2026
989686f
fix: update GameSettingsTest for turnTimeLimit field
DDINGJOO Jan 25, 2026
2db7a8f
fix: update WordChainSessionSpec for new time calculation logic
DDINGJOO Jan 25, 2026
007b7da
Merge pull request #539 from Language-Study-Prooject/develop
DDINGJOO Jan 25, 2026
9431b89
fix: revert buildspec to build+package only, let Deploy stage handle …
DDINGJOO Jan 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ServerlessFunction/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dependencies {
implementation 'software.amazon.awssdk:url-connection-client'
implementation 'software.amazon.awssdk:ssm'
implementation 'software.amazon.awssdk:scheduler'
implementation 'software.amazon.awssdk:sqs'

// AWS X-Ray SDK (다운스트림 서비스 추적용)
implementation 'com.amazonaws:aws-xray-recorder-sdk-core:2.15.0'
Expand Down
5 changes: 4 additions & 1 deletion ServerlessFunction/buildspec-dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,10 @@ phases:
--capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND \
--no-confirm-changeset \
--no-fail-on-empty-changeset \
--parameter-overrides Environment=$ENVIRONMENT
--parameter-overrides \
Environment=$ENVIRONMENT \
ExistingCognitoUserPoolId=ap-northeast-2_ezDwzFCzR \
ExistingCognitoClientId=4ns077jcr1pkue2vvisr6qdpu5
- echo "Deployment completed on $(date)"

cache:
Expand Down
23 changes: 8 additions & 15 deletions ServerlessFunction/buildspec-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ env:
SAM_CLI_TELEMETRY: 0
GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.caching=true"
ENVIRONMENT: prod
STACK_NAME: group2-englishstudy-prod

phases:
install:
Expand All @@ -28,23 +27,17 @@ phases:
- echo "Building SAM application for $ENVIRONMENT..."
- cd $CODEBUILD_SRC_DIR/ServerlessFunction
- sam build --parallel --cached
- echo "Build completed"
- echo "Packaging SAM application..."
- sam package --s3-bucket group2-englishstudy-pipeline-artifacts --s3-prefix sam-packages/$ENVIRONMENT --output-template-file packaged-template.yaml

post_build:
commands:
- echo "Deploying to $ENVIRONMENT environment..."
- cd $CODEBUILD_SRC_DIR/ServerlessFunction
- |
sam deploy \
--stack-name $STACK_NAME \
--s3-bucket group2-englishstudy-pipeline-artifacts \
--s3-prefix sam-deploy/prod \
--region ap-northeast-2 \
--capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND \
--no-confirm-changeset \
--no-fail-on-empty-changeset \
--parameter-overrides Environment=$ENVIRONMENT
- echo "Deployment completed on $(date)"
- echo "Build completed on $(date)"

artifacts:
files:
- packaged-template.yaml
base-directory: ServerlessFunction

cache:
paths:
Expand Down
23 changes: 8 additions & 15 deletions ServerlessFunction/buildspec-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ env:
SAM_CLI_TELEMETRY: 0
GRADLE_OPTS: "-Dorg.gradle.daemon=false -Dorg.gradle.parallel=true -Dorg.gradle.caching=true"
ENVIRONMENT: test
STACK_NAME: group2-englishstudy-test

phases:
install:
Expand All @@ -28,23 +27,17 @@ phases:
- echo "Building SAM application for $ENVIRONMENT..."
- cd $CODEBUILD_SRC_DIR/ServerlessFunction
- sam build --parallel --cached
- echo "Build completed"
- echo "Packaging SAM application..."
- sam package --s3-bucket group2-englishstudy-pipeline-artifacts --s3-prefix sam-packages/$ENVIRONMENT --output-template-file packaged-template.yaml

post_build:
commands:
- echo "Deploying to $ENVIRONMENT environment..."
- cd $CODEBUILD_SRC_DIR/ServerlessFunction
- |
sam deploy \
--stack-name $STACK_NAME \
--resolve-s3 \
--s3-prefix $STACK_NAME \
--region ap-northeast-2 \
--capabilities CAPABILITY_IAM CAPABILITY_AUTO_EXPAND \
--no-confirm-changeset \
--no-fail-on-empty-changeset \
--parameter-overrides Environment=$ENVIRONMENT
- echo "Deployment completed on $(date)"
- echo "Build completed on $(date)"

artifacts:
files:
- packaged-template.yaml
base-directory: ServerlessFunction

cache:
paths:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.sns.SnsClient;
import software.amazon.awssdk.services.sqs.SqsClient;
import software.amazon.awssdk.services.ssm.SsmClient;

/**
Expand Down Expand Up @@ -60,7 +61,12 @@ public final class AwsClients {
private static final SsmClient SSM_CLIENT = SsmClient.builder()
.overrideConfiguration(XRAY_CONFIG)
.build();


// SQS
private static final SqsClient SQS_CLIENT = SqsClient.builder()
.overrideConfiguration(XRAY_CONFIG)
.build();

private AwsClients() {
// 인스턴스화 방지
}
Expand Down Expand Up @@ -104,4 +110,8 @@ public static ComprehendClient comprehend() {
public static SsmClient ssm() {
return SSM_CLIENT;
}

public static SqsClient sqs() {
return SQS_CLIENT;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,18 @@ public final class EnvConfig {
private EnvConfig() {
// 유틸리티 클래스 - 인스턴스화 방지
}


/**
* 선택적 환경 변수를 가져옵니다.
* 환경 변수가 설정되지 않은 경우 null을 반환합니다.
*
* @param name 환경 변수 이름
* @return 환경 변수 값 또는 null
*/
public static String get(String name) {
return System.getenv(name);
}

/**
* 필수 환경 변수를 가져옵니다.
* 환경 변수가 설정되지 않았거나 빈 문자열인 경우 IllegalStateException을 발생시킵니다.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.mzc.secondproject.serverless.common.util;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;

Expand All @@ -10,9 +12,25 @@
* JSON 파싱 관련 공통 유틸리티
*/
public class JsonUtil {


private static final Gson GSON = new GsonBuilder().create();

private JsonUtil() {
}

/**
* 객체를 JSON 문자열로 변환
*/
public static String toJson(Object obj) {
return GSON.toJson(obj);
}

/**
* JSON 문자열을 객체로 변환
*/
public static <T> T fromJson(String json, Class<T> clazz) {
return GSON.fromJson(json, clazz);
}

// 응답에서 JSON 부분만 추출
public static String extractJson(String response) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.mzc.secondproject.serverless.domain.badge.repository.BadgeRepository;
import com.mzc.secondproject.serverless.domain.badge.strategy.BadgeConditionStrategy;
import com.mzc.secondproject.serverless.domain.badge.strategy.BadgeConditionStrategyFactory;
import com.mzc.secondproject.serverless.domain.notification.service.NotificationPublisher;
import com.mzc.secondproject.serverless.domain.stats.model.UserStats;
import com.mzc.secondproject.serverless.domain.stats.repository.UserStatsRepository;
import org.slf4j.Logger;
Expand All @@ -24,20 +25,23 @@ public class BadgeService {

private final BadgeRepository badgeRepository;
private final UserStatsRepository userStatsRepository;

private final NotificationPublisher notificationPublisher;

/**
* 기본 생성자 (Lambda에서 사용)
*/
public BadgeService() {
this(new BadgeRepository(), new UserStatsRepository());
this(new BadgeRepository(), new UserStatsRepository(), NotificationPublisher.getInstance());
}

/**
* 의존성 주입 생성자 (테스트 용이성)
*/
public BadgeService(BadgeRepository badgeRepository, UserStatsRepository userStatsRepository) {
public BadgeService(BadgeRepository badgeRepository, UserStatsRepository userStatsRepository,
NotificationPublisher notificationPublisher) {
this.badgeRepository = badgeRepository;
this.userStatsRepository = userStatsRepository;
this.notificationPublisher = notificationPublisher;
}

/**
Expand Down Expand Up @@ -98,6 +102,15 @@ public List<UserBadge> checkAndAwardBadges(String userId, UserStats stats) {
badgeRepository.save(badge);
newBadges.add(badge);
logger.info("Badge awarded: userId={}, badge={}", userId, type.name());

// 알림 발행
notificationPublisher.publishBadgeEarned(
userId,
type.name(),
type.getName(),
type.getDescription(),
badge.getImageUrl()
);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,25 @@ public enum MessageType {

// 방 관련 메시지 타입
ROOM_STATUS_CHANGE("room_status_change", "방 상태 변경"),
HOST_CHANGE("host_change", "방장 변경");
HOST_CHANGE("host_change", "방장 변경"),

// 투표 관련 메시지 타입
POLL_CREATE("poll_create", "투표 생성"),
POLL_VOTE("poll_vote", "투표 참여"),
POLL_END("poll_end", "투표 종료"),

// 끝말잇기(Word Chain) 게임 메시지 타입
WORDCHAIN_START("wordchain_start", "끝말잇기 시작"),
WORDCHAIN_TURN("wordchain_turn", "턴 변경"),
WORDCHAIN_CORRECT("wordchain_correct", "정답"),
WORDCHAIN_WRONG("wordchain_wrong", "오답"),
WORDCHAIN_TIMEOUT("wordchain_timeout", "시간 초과"),
WORDCHAIN_ELIMINATED("wordchain_eliminated", "탈락"),
WORDCHAIN_END("wordchain_end", "끝말잇기 종료"),

// 유틸리티 메시지 타입
CLEAR_CHAT("clear_chat", "채팅 삭제"),
LEAVE_ROOM("leave_room", "채팅방 나가기");

private final String code;
private final String displayName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ public enum ChattingErrorCode implements DomainErrorCode {
GAME_NOT_ALLOWED_IN_CHAT_ROOM("GAME_007", "게임은 게임 방에서만 시작할 수 있습니다", 400),
GAME_RESTART_NOT_ALLOWED("GAME_008", "게임 진행 중에는 재시작할 수 없습니다", 400),
GAME_START_NOT_HOST("GAME_009", "방장만 게임을 시작할 수 있습니다", 403),
GAME_ACTION_FAILED("GAME_010", "게임 액션 처리에 실패했습니다", 400),

// 일반 입력 에러
INVALID_INPUT("INPUT_001", "유효하지 않은 입력입니다", 400),
;

private static final String DOMAIN = "CHATTING";
Expand Down
Loading