Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
b713225
[Setup/#1] chore: application.yml, application-local.yml 기본 환경 설정 추가
Donghwan814 Jul 4, 2026
30326e0
[Setup/#1] chore: .env.example 추가
Donghwan814 Jul 6, 2026
7eda785
[Setup/#1] feat: GlobalEntity 기능 구현
Donghwan814 Jul 6, 2026
32a38ee
[Setup/#1] feat: user 엔티티 설계
Donghwan814 Jul 6, 2026
1c65a11
[Setup/#1] feat: social_account 엔티티 설계
Donghwan814 Jul 6, 2026
a59e895
[Setup/#1] feat: content_category 엔티티 설계
Donghwan814 Jul 6, 2026
6b26883
[Setup/#1] feat: learning_content 엔티티 설계
Donghwan814 Jul 6, 2026
87979a5
[Setup/#1] feat: standard_pronunciation 엔티티 설계
Donghwan814 Jul 6, 2026
4bba65b
[Setup/#1] feat: ranking 엔티티 설계
Donghwan814 Jul 6, 2026
ec8b029
[Setup/#1] feat: wrong_answer 엔티티 설계
Donghwan814 Jul 6, 2026
ed4ee56
[Setup/#1] feat: pronunciation_attempt 엔티티 설계
Donghwan814 Jul 6, 2026
f7edfda
[Setup/#1] feat: audio_file 엔티티 설계
Donghwan814 Jul 6, 2026
8be6aaa
[Setup/#1] feat: phoneme_score 엔티티 설계
Donghwan814 Jul 6, 2026
996f578
[Setup/#1] feat: feedback 엔티티 설계
Donghwan814 Jul 6, 2026
21d1788
[Setup/#1] feat: game_result 엔티티 설계
Donghwan814 Jul 6, 2026
d21c87f
[Setup/#1] feat: game_field_table 엔티티 설계
Donghwan814 Jul 6, 2026
ea84669
[Setup/#1] fix: GlobalEntity 리스너 연결 및 updated_at 컬럼명 수정
Donghwan814 Jul 6, 2026
db93bd9
[Setup/#1] fix: 엔티티 PK 타입 int → Long 변경 및 User status enum 적용
Donghwan814 Jul 6, 2026
7529cb0
[Setup/#1] feat: SecurityConfig 기본 설정 추가
Donghwan814 Jul 6, 2026
9398023
[Fix/Setup#1] Fix: PR 기반 오류 수정
Donghwan814 Jul 8, 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
33 changes: 33 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Application
APP_BASE_URL=http://localhost:8080
APP_FRONTEND_BASE_URL=http://localhost:8080
APP_CORS_ALLOWED_ORIGINS=http://localhost:8080

# Database
DB_URL=jdbc:mysql://localhost:3306/loginmodule?serverTimezone=Asia/Seoul&characterEncoding=UTF-8
DB_USERNAME=root
DB_PASSWORD=change-me
DB_DRIVER_CLASS_NAME=com.mysql.cj.jdbc.Driver
JPA_DDL_AUTO=update
JPA_SHOW_SQL=true

# JWT
# Must be at least 32 bytes.
JWT_SECRET=change-me-to-at-least-32-bytes-secret
JWT_ACCESS_EXP_MIN=60
JWT_REFRESH_EXP_DAY=30

# OAuth redirect base
# Default: ${APP_FRONTEND_BASE_URL}/oauth/callback
# OAUTH_REDIRECT_BASE_URI=http://localhost:8080/oauth/callback

# Google Developer Console
GOOGLE_CLIENT_ID=change-me
GOOGLE_CLIENT_SECRET=change-me
# GOOGLE_REDIRECT_URI=http://localhost:8080/oauth/callback/google

# Meta for Developers / Facebook Login
FACEBOOK_CLIENT_ID=change-me
FACEBOOK_CLIENT_SECRET=change-me
FACEBOOK_GRAPH_API_VERSION=v21.0
# FACEBOOK_REDIRECT_URI=http://localhost:8080/oauth/callback/facebook
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,6 @@ out/

### VS Code ###
.vscode/

### .env ###
.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.daehanforeigner.capstone.domain.audio_file.entity;

import com.daehanforeigner.capstone.domain.pronunciation_attempt.PronunciationAttempt;
import com.daehanforeigner.capstone.global.entity.GlobalEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "audio_file")
public class AudioFile extends GlobalEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "audio_file_id")
private Long audioFileId;

@ManyToOne
@JoinColumn(name = "attempt_id")
private PronunciationAttempt attempt;

@Column(name = "file_url") // 오디오 파일 URL
private String fileUrl;

@Column(name = "file_size") // 오디오 파일 크기
private int fileSize;

@Column(name = "duration_ms") // 오디오 파일 길이 (밀리초 단위)
private int durationMs;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.daehanforeigner.capstone.domain.content_category;

public enum CategoryType {
BASIC, // 기본 학습
CULTURE // 문화 학습
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.daehanforeigner.capstone.domain.content_category;

import com.daehanforeigner.capstone.global.entity.GlobalEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "content_category")
public class ContentCategory extends GlobalEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "category_id")
private Long categoryId;

@Enumerated(EnumType.STRING)
@Column(name = "type")
private CategoryType type;

@Column(name = "name") // 카테고리 이름 ex) 학습, 드라마 대사, K문화, 신조어 등
private String name;

@Column(name = "description") // 카테고리 설명
private String description;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.daehanforeigner.capstone.domain.feedback.entity;

import com.daehanforeigner.capstone.domain.pronunciation_attempt.PronunciationAttempt;
import com.daehanforeigner.capstone.domain.user.entity.NativeLangauge;
import com.daehanforeigner.capstone.global.entity.GlobalEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "feedback")
public class Feedback extends GlobalEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "feedback_id")
private Long feedbackId;

@ManyToOne
@JoinColumn(name = "attempt_id")
private PronunciationAttempt attempt;

@Column(name = "content") // 피드백 내용
private String content;

@Enumerated(EnumType.STRING)
@Column(name = "language") // 피드백 언어
private NativeLangauge language;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.daehanforeigner.capstone.domain.game_field_table.entity;

import com.daehanforeigner.capstone.domain.game_result.entity.GameResult;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "game_field_table")
public class GameFieldTable {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "game_sentence_id") // 게임 문장 ID
private Long gameSentenceId;

@ManyToOne
@JoinColumn(name = "game_result_id") // 게임 결과 ID
private GameResult gameResult;

@Column(name = "is_sentence") // 문장 여부
private boolean isSentence;

@Column(name = "game_field") // 내용
private String gameField;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.daehanforeigner.capstone.domain.game_result.entity;

import com.daehanforeigner.capstone.domain.content_category.ContentCategory;
import com.daehanforeigner.capstone.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "game_result")
public class GameResult {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "game_result_id")
private Long gameResultId;

@ManyToOne
@JoinColumn(name = "user_id")
private User user;

@ManyToOne
@JoinColumn(name = "category_id")
private ContentCategory category;

@Column(name = "score")
private int score;

@Column(name = "is_passed")
private boolean isPassed;

@Column(name = "played_at")
private LocalDateTime playedAt;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.daehanforeigner.capstone.domain.learning_content;

public enum ContentType {
SYLLABLE, // 음절
WORD, // 단어
SENTENCE // 문장
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.daehanforeigner.capstone.domain.learning_content;

public enum Difficulty {
BEGINNER, // 초급
INTERMEDIATE, // 중급
ADVANCED // 고급
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.daehanforeigner.capstone.domain.learning_content;

import com.daehanforeigner.capstone.domain.content_category.ContentCategory;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "learning_content")
public class LearningContent {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "content_id")
private Long contentId;

@ManyToOne
@JoinColumn(name = "category_id")
private ContentCategory contentCategory;

@Enumerated(EnumType.STRING)
@Column(name = "content_type") // 음절, 단어, 문장
private ContentType contentType;

@Enumerated(EnumType.STRING)
@Column(name = "difficulty") // 초급, 중급, 고급
private Difficulty difficulty;

@Column(name = "text") // 학습 텍스트
private String text;

@Column(name = "meaning") // 의미
private String meaning;

@Column(name = "example_sentence") // 예문
private String exampleSentence;

@Column(name = "pronunciation_guide") // 발음 가이드
private String pronunciationGuide;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.daehanforeigner.capstone.domain.phoneme_score.entity;

import com.daehanforeigner.capstone.domain.pronunciation_attempt.PronunciationAttempt;
import com.daehanforeigner.capstone.global.entity.GlobalEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "phoneme_score")
public class PhonemeScore extends GlobalEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "phoneme_score_id")
private Long phonemeScoreId;

@ManyToOne
@JoinColumn(name = "attempt_id")
private PronunciationAttempt attempt;

@Column(name = "phoneme") // 음소
private String phoneme;

@Column(name = "score") // 점수
private int score;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.daehanforeigner.capstone.domain.pronunciation_attempt;

import com.daehanforeigner.capstone.domain.learning_content.LearningContent;
import com.daehanforeigner.capstone.domain.user.entity.User;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "pronunciation_attempt")
public class PronunciationAttempt {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "attempt_id")
private Long attemptId;

@ManyToOne
@JoinColumn(name = "user_id")
private User user;

@ManyToOne
@JoinColumn(name = "content_id")
private LearningContent learningContent;

@Column(name = "recognized_text") // STT 인식 결과
private String recognizedText;

@Column(name = "voice_score") // 발음 점수
private int voiceScore;

@Column(name = "lip_score") // 입모양 점수
private int lipScore;

@Column(name = "accuracy") // 정확도 (음성 70%, 입모양 30%)
private double accuracy;

@Column(name = "is_passed") // 합격 여부 (85% 이상 합격)
private boolean isPassed;

@Column(name = "user_pitch_data", columnDefinition = "json") // 사용자의 피치 데이터 (JSON 형식)
private String userPitchData;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.daehanforeigner.capstone.domain.ranking.entity;

import com.daehanforeigner.capstone.domain.user.entity.User;
import com.daehanforeigner.capstone.global.entity.GlobalEntity;
import jakarta.persistence.*;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "ranking")
public class Ranking extends GlobalEntity {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "rank_id")
private Long rankId;

@ManyToOne
@JoinColumn(name = "user_id")
private User user;

@Column(name = "best_score")
private int bestScore;

@Column(name = "spoken_word_count") // 말한 단어 수
private int spokenWordCount;
}
Loading