Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
7e6bc95
[Fix] 출석 및 보증금 ID 타입 정합성 수정
issuejong Jun 16, 2026
0aff7b1
[Fix] 질문 익명 번호 유니크 제약 정합성 수정
issuejong Jun 16, 2026
5179e64
[Fix] 질문 상세 조회 N+1 개선
issuejong Jun 16, 2026
ef72837
[Fix] 좋아요 카운트 동시성 보강
issuejong Jun 16, 2026
ebd8030
[Fix] 익명 번호 역할별 유니크 제약 추가
issuejong Jun 16, 2026
1088616
Merge pull request #208 from pirogramming/fix/#207
issuejong Jun 16, 2026
63e8aec
feat: 동전 즉시 업데이트 수정 완료
Jun 16, 2026
0630246
Merge pull request #210 from pirogramming/feat/209
lilyyang0077 Jun 16, 2026
5bd5803
[feat] 질문 디테일 탭에서 목록으로 버튼 추가
kdhye1119 Jun 18, 2026
0e5db13
[feat] QnA -> 현재 세션 으로 이름 변경
kdhye1119 Jun 18, 2026
4ff3ac4
[feat] 이해도 체크 올리기 전에는 이해도 바 안뜨게 하기
kdhye1119 Jun 18, 2026
ffdf234
Merge branch 'develop' into Feat/#212
kdhye1119 Jun 18, 2026
8460414
Merge pull request #213 from pirogramming/Feat/#212
kdhye1119 Jun 18, 2026
0784a06
[bug] 사진 오류 및 리다이렉트 에러 수정
kdhye1119 Jun 18, 2026
4fc099d
Merge pull request #215 from pirogramming/Bug/#214
kdhye1119 Jun 18, 2026
40a330f
fix: 요일 중복되는 것 수정 & 화목토 정렬 추가
Jun 18, 2026
6b8f37e
fix: 주차별 상태 조회 응답 데이터 파싱 수정
Jun 18, 2026
8084246
fix: 주차별 상태 조회 응답 파싱 및 데이터 정합성 수정
Jun 18, 2026
210dd19
[Chore] 피로체크 메인화면 (부원용) 메뉴 리네이밍
plumbestie Jun 18, 2026
2700d30
Merge pull request #217 from pirogramming/feat/211
lilyyang0077 Jun 18, 2026
d7b98b1
fix: 과제 상태명 수정
Jun 18, 2026
476b4fd
Merge pull request #219 from pirogramming/feat/218
lilyyang0077 Jun 18, 2026
e43e7b3
[Chore] 커리큘럼 링크 범위 수정
plumbestie Jun 18, 2026
35b1c8c
feat: 자동 보증금 재로딩 기능 추가
Jun 18, 2026
c85bce3
feat: 요일별 저장 버튼 제거
Jun 18, 2026
0c6b394
style: 출석 상태 라벨 표시 형식 개선
Jun 18, 2026
126f021
Merge pull request #221 from pirogramming/Chore/#216
plumbestie Jun 18, 2026
2dfe837
Merge pull request #222 from pirogramming/feat/220
lilyyang0077 Jun 18, 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
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

@Service
Expand Down Expand Up @@ -248,17 +249,21 @@ public StudentWeeklyStatusResponse getStudentWeeklyStatus(
List<StudySession> sessions =
curriculumRepository.findByWeek(week);

List<DayStatusResponse> dayResponses = new ArrayList<>();
List<LocalDate> sessionDates = sessions.stream()
.map(StudySession::getSessionDate)
.distinct()
.sorted()
.toList();

for (StudySession session : sessions) {
List<DayStatusResponse> dayResponses = new ArrayList<>();

LocalDate sessionDate = session.getSessionDate();
for (LocalDate sessionDate : sessionDates) {

String day =
sessionDate.getDayOfWeek().toString();
String day = sessionDate.getDayOfWeek().toString();

/*
* 과제 조회
* 과제 date를 요일/sessionDate 기준으로 조회하는 기존 방식 유지
*/
List<Assignment> assignments =
assignmentRepository.findBySessionDate(sessionDate);
Expand Down Expand Up @@ -293,12 +298,14 @@ public StudentWeeklyStatusResponse getStudentWeeklyStatus(

/*
* 출석 조회
* attendance는 attendance_code의 날짜 기준으로 계산하는 기존 방식 유지
*/
List<AttendanceCode> attendanceCodes =
attendanceCodeRepository.findByAttendanceDate(sessionDate);

List<AttendanceStatusResponse> attendanceResponses =
attendanceCodes.stream()
.sorted(Comparator.comparing(AttendanceCode::getAttendanceOrder))
.map(code -> {

Attendance attendance =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;


public interface AttendanceCodeRepository extends JpaRepository<AttendanceCode, Long> {
public interface AttendanceCodeRepository extends JpaRepository<AttendanceCode, Integer> {

// [추가] 모든 활성화된 코드를 한 번에 만료 처리 (벌크 연산)
@Modifying
Expand All @@ -34,4 +33,3 @@ public interface AttendanceCodeRepository extends JpaRepository<AttendanceCode,
List<AttendanceCode> findByAttendanceDate(LocalDate attendanceDate);
}


Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
package com.example.Piroin.project.domain.attendance.repository;

import com.example.Piroin.project.domain.attendance.entity.AttendanceCode;
import com.example.Piroin.project.domain.curriculum.entity.StudySession;
import com.example.Piroin.project.domain.user.entity.User;
import com.example.Piroin.project.domain.attendance.entity.Attendance;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

public interface AttendanceRepository extends JpaRepository<Attendance, Long> {
public interface AttendanceRepository extends JpaRepository<Attendance, Integer> {

Optional<Attendance> findById(Integer id);


// 연관관계 필드명이 attendanceCode 라면 내부 ID인 Id를 조합하여 명명
Optional<Attendance> findByUserIdAndAttendanceCodeId(Long userId, Long attendanceCodeId);


int countByUserAndStatusFalse(User user);

// 1. 특정 출석 코드 ID에 해당하는 결석 데이터 조회
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public AttendanceMarkResponse markAttendance(Long userId, String inputCode) {
// 혹은 조회된 code의 날짜/차수 정보를 기반으로 기존 출석 기록을 찾아야 합니다.
// (여기서는 이전 답변 시나리오 1인 'attendanceCodeId'로 매핑했다고 가정했을 때의 예시입니다.)
Attendance attendance = attendanceRepository
.findByUserIdAndAttendanceCodeId(userId, Long.valueOf(code.getId()))
.findByUserIdAndAttendanceCodeId(userId, code.getId())
.orElse(null);

// 해당 사용자와 출석 코드에 대한 출석 기록이 존재하지 않는 경우
Expand Down Expand Up @@ -323,4 +323,3 @@ public List<AttendanceStatusRes> findByUserId(Integer userId) {


}

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import java.util.List;
import java.util.Optional;

public interface DepositRepository extends JpaRepository<Deposit, Long> {
public interface DepositRepository extends JpaRepository<Deposit, Integer> {
Optional<Deposit> findByUser(User user);

Optional<Deposit> findByUserId(Long userId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.Piroin.project.domain.question.entity;

import com.example.Piroin.project.domain.user.entity.User;
import com.example.Piroin.project.domain.user.enums.Role;
import jakarta.persistence.*;
import lombok.*;

Expand All @@ -11,12 +12,12 @@
name = "question_anonymous_identity",
uniqueConstraints = {
@UniqueConstraint(
name = "uq_question_anon_question_user",
name = "uq_question_anonymous_identity_question_user",
columnNames = {"question_id", "user_id"}
),
@UniqueConstraint(
name = "uq_question_anon_question_no",
columnNames = {"question_id", "anonymous_no"}
name = "uq_question_anonymous_identity_question_role_no",
columnNames = {"question_id", "role", "anonymous_no"}
)
}
)
Expand All @@ -41,7 +42,10 @@ public class QuestionAnonymousIdentity {
@Column(name = "anonymous_no", nullable = false)
private Integer anonymousNo;

@Enumerated(EnumType.STRING)
@Column(name = "role", nullable = false)
private Role role;

@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,37 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;
import java.util.Set;

public interface QuestionAnonymousIdentityRepository extends JpaRepository<QuestionAnonymousIdentity, Long> {

// 해당 질문에서 유저의 익명 번호 조회
// 용도: 댓글 작성 시 이미 번호가 있는지 확인
Optional<QuestionAnonymousIdentity> findByQuestionAndUser(Question question, User user);

// 해당 질문에서 특정 역할(MEMBER/ADMIN)의 익명 번호 수 조회
// 용도: 새 익명 번호 발급 시 역할별로 따로 카운트
// MEMBER → 익명1, 익명2... / ADMIN → 운영진1, 운영진2...
int countByQuestionAndUser_Role(Question question, Role role);
// 질문 상세 조회용: 댓글 작성자들의 익명 번호를 한 번에 조회
@Query("""
SELECT identity
FROM QuestionAnonymousIdentity identity
JOIN FETCH identity.user
WHERE identity.question = :question
AND identity.user.id IN :userIds
""")
List<QuestionAnonymousIdentity> findByQuestionAndUserIds(
@Param("question") Question question,
@Param("userIds") Set<Long> userIds
);

@Query("SELECT COALESCE(MAX(a.anonymousNo), 0) FROM QuestionAnonymousIdentity a " + "WHERE a.question = :question AND a.user.role = :role")
@Query("""
SELECT COALESCE(MAX(identity.anonymousNo), 0)
FROM QuestionAnonymousIdentity identity
WHERE identity.question = :question
AND identity.role = :role
""")
int findMaxAnonymousNoByQuestionAndRole(
@Param("question") Question question,
@Param("role") Role role
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@

public interface QuestionCommentRepository extends JpaRepository<QuestionComment, Long> {
/*
특정 질문의 삭제되지 않은 최상위 댓글 목록(등록순)
parentComment가 null인 것 = 대댓글이 아닌 최상위 댓글
용도: 질문 상세 페이지에서 댓글 목록 표시 시
질문 상세 조회용 댓글 목록을 한 번에 가져온다.
댓글 작성자와 부모 댓글을 함께 로딩해 댓글/대댓글 DTO 조립 중 N+1 조회를 피한다.
*/
List<QuestionComment> findByQuestionAndParentCommentIsNullAndDeletedAtIsNullOrderByCreatedAtAsc(Question question);
@Query("""
SELECT comment
FROM QuestionComment comment
JOIN FETCH comment.user
LEFT JOIN FETCH comment.parentComment
WHERE comment.question = :question
AND comment.deletedAt IS NULL
ORDER BY comment.createdAt ASC, comment.id ASC
""")
List<QuestionComment> findByQuestionWithUserAndParentComment(@Param("question") Question question);

/*
질문 목록 미리보기용 최상위 댓글 3개를 질문별로 한 번에 조회한다.
Expand All @@ -25,7 +33,7 @@ public interface QuestionCommentRepository extends JpaRepository<QuestionComment
SELECT ranked.question_id AS "questionId",
ranked.id AS "commentId",
ranked.user_id AS "userId",
u.role AS "userRole",
COALESCE(qai.role, u.role) AS "userRole",
ranked.content AS "content",
ranked.image_url AS "imageUrl",
ranked.created_at AS "createdAt",
Expand Down Expand Up @@ -64,12 +72,6 @@ WHERE qc.question_id IN (:questionIds)
""")
List<CommentCountRow> countByQuestionIds(@Param("questionIds") List<Long> questionIds);

/*
특정 댓글의 대댓글 목록(등록순)
용도: 댓글 아래 대댓글을 가져올 때
*/
List<QuestionComment> findByParentCommentAndDeletedAtIsNullOrderByCreatedAtAsc(QuestionComment parentComment);

interface PreviewCommentRow {
Long getQuestionId();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import com.example.Piroin.project.domain.curriculum.entity.StudySession;
import com.example.Piroin.project.domain.question.entity.Question;
import jakarta.persistence.LockModeType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;
Expand All @@ -19,4 +23,28 @@ public interface QuestionRepository extends JpaRepository<Question, Long> {
용도: 질문 상세 조회, 수정, 삭제, 좋아요 처리 시
*/
Optional<Question> findByIdAndDeletedAtIsNull(Long id);
}

/*
질문 상세 조회용: 질문 작성자를 함께 가져와 상세 DTO 조립 중 추가 조회를 피한다.
*/
@Query("""
SELECT question
FROM Question question
JOIN FETCH question.user
WHERE question.id = :id
AND question.deletedAt IS NULL
""")
Optional<Question> findDetailByIdAndDeletedAtIsNull(@Param("id") Long id);

/*
좋아요 카운트 갱신용: 같은 질문에 대한 동시 토글 요청을 직렬화해 likeCount lost update를 방지한다.
*/
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("""
SELECT question
FROM Question question
WHERE question.id = :id
AND question.deletedAt IS NULL
""")
Optional<Question> findByIdAndDeletedAtIsNullForUpdate(@Param("id") Long id);
}
Loading
Loading