Conversation
… and invitation code checks
… logic in StudyService
…sor and take parameters
…tialize in GroupService
| @Query('take', new DefaultValuePipe(10), new RequiredIntPipe('take')) | ||
| take: number | ||
| ) { | ||
| return await this.studyService.getStudyGroups({ |
There was a problem hiding this comment.
나중에 페이지네이션 필요할 수도 있을거같은데 GroupService.getGroups() 처럼 total도 받는것도 나쁘지 않을 것 같습니다! 물론 명세서가 커서 기반일지 오프셋 방식일지는 모르겠지만...!
| export class StudyService { | ||
| constructor(private readonly prisma: PrismaService) {} | ||
|
|
||
| async createStudyGroup(userId: number, dto: CreateStudyDto) { |
There was a problem hiding this comment.
getStudyGroups, getStudyGroup이랑 다르게 create랑 update는 raw 모델 그대로 나가는거같은데 의도된건가요?
There was a problem hiding this comment.
codedang/apps/backend/apps/client/src/group/group.service.ts
Lines 1332 to 1375 in dcf54e4
codedang/apps/backend/apps/client/src/user/user.service.ts
Lines 689 to 724 in dcf54e4
codedang/apps/backend/apps/client/src/contest/contest.service.ts
Lines 259 to 308 in dcf54e4
client 내부에 Post, Patch 요청을 찾아보니깐 대부분이 Prisma 객체를 그대로 return 하는 경우가 많이 있어서 위와 같이 구현하였습니다
There was a problem hiding this comment.
근데 형님 친절한 코드 붙여넣기 감동이네요 근데 저희 말 편하게 하면 안되나요 친해지고 싶은데~
Choi-Jung-Hyeon
left a comment
There was a problem hiding this comment.
저에게는 룩굿투미인데 도현이는 언제쯤 룩해줄까요
| capacity: studyGroup.studyInfo?.capacity, | ||
| tags: studyGroup.groupTag.map((tag) => tag.tag.name), | ||
| isPublic: !studyGroup.studyInfo?.invitationCode, | ||
| isJoined: userId ? studyGroup._count.userGroup > 0 : false |
There was a problem hiding this comment.
이건 그냥 해결된걸로 하시죠 ㅋㅋ 문제 없을듯
| export class StudyService { | ||
| constructor(private readonly prisma: PrismaService) {} | ||
|
|
||
| async createStudyGroup(userId: number, dto: CreateStudyDto) { |
| export class StudyService { | ||
| constructor(private readonly prisma: PrismaService) {} | ||
|
|
||
| async createStudyGroup(userId: number, dto: CreateStudyDto) { |
There was a problem hiding this comment.
근데 형님 친절한 코드 붙여넣기 감동이네요 근데 저희 말 편하게 하면 안되나요 친해지고 싶은데~
… for joining ended groups
8401e7a352ba68d9fac8d8f a405f8e
|
지난번 Init 회의 이후에 수정사항이 있어서 해당 내역 반영했습니다.
|
Choi-Jung-Hyeon
left a comment
There was a problem hiding this comment.
도현이는 또 한참 안보겠지 이제
| let newEndTime: Date | undefined = undefined | ||
| if (durationHours !== undefined) { | ||
| newEndTime = new Date(studyGroup.createTime) | ||
| newEndTime.setHours(newEndTime.getHours() + durationHours) |
There was a problem hiding this comment.
저 궁금한게 생성 시점부터 총 N시간으로 무조건 계산하는 건가요? 수정 시점부터 N시간 연장은 안되는거죠
There was a problem hiding this comment.
현재 스터디 그룹 생성 시에, 종료 예정 시간을 최대 24시간까지 설정이 가능한데, 이에 대한 PATCH 요청으로 시간을 추가 연장하는 것은 좀 애매할 것 같습니다.
There was a problem hiding this comment.
아마도 시간 연장에 대한 별도의 API와 FE에서의 입력창이 구현되어야 할 것 같아요!
| let newEndTime: Date | undefined = undefined | ||
| if (durationHours !== undefined) { | ||
| newEndTime = new Date(studyGroup.createTime) | ||
| newEndTime.setHours(newEndTime.getHours() + durationHours) |
There was a problem hiding this comment.
그리고 역대급 오지랖이긴 한데 서머타임 DST를 쓰는 나라에서는... setHours()를 쓰면 안된대요 ㅋㅋ .getTime() + durationHours * 1000 * 60 * 60 으로 해야된대요 개웃기네 ㅋㅋㅋ
There was a problem hiding this comment.
그런데 한국은 서머타임 적용이 안되어서 크게 문제는 없지 않아요?
There was a problem hiding this comment.
서버가 한국에 있다는 보장이 없어서 일단 반영해뒀습니다 ㅋㅋ
| })) | ||
| } | ||
|
|
||
| async getStudyGroup(groupId: number, userId: number) { |
There was a problem hiding this comment.
얘는 진행중인 스터디 검사 안해도 되나요? s붙은 애는 하는거같아요
There was a problem hiding this comment.
어제 코드 수정만 하고 커밋을 안했네요 ㅋㅋ
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request introduces a new 'Study' module, enabling users to create, manage, and join study groups. This includes new DTOs for study group data, a controller for API endpoints, and a service layer for business logic and database interactions. Database schema changes were also made to support study group information and group-specific tags. Feedback includes optimizing the getStudyGroups method to prevent performance issues by efficiently fetching leader information and member counts, and adjusting the invitationCode validation in UpdateStudyDto to correctly handle null values for transitioning study groups from private to public.
| userGroup: { | ||
| select: { | ||
| user: { | ||
| select: { | ||
| username: true | ||
| } | ||
| }, | ||
| isGroupLeader: true | ||
| } | ||
| }, |
There was a problem hiding this comment.
getStudyGroups 메소드에서 각 스터디 그룹의 모든 멤버를 가져오는 방식은 성능 문제를 일으킬 수 있습니다. 스터디 그룹에 멤버가 많을 경우 불필요하게 많은 데이터를 조회하게 됩니다.
리더의 정보와 총 멤버 수는 Prisma 쿼리에서 더 효율적으로 가져올 수 있습니다. userGroup 관계에서는 리더만 조회하고, 총 멤버 수는 _count를 사용하는 것을 제안합니다.
// In prisma.group.findMany
select: {
// ... other fields
userGroup: {
where: { isGroupLeader: true },
select: {
user: {
select: {
username: true
}
}
}
},
_count: {
select: {
userGroup: true // Total members
}
},
// ... other fields
}
// Then in the map function
leader: studyGroup.userGroup[0]?.user.username,
currentMember: studyGroup._count.userGroup,isJoined 필드를 처리하기 위해 현재처럼 조건부 _count를 사용하면 총 멤버 수를 가져오는 _count와 충돌하게 됩니다. isJoined 상태는 별도의 쿼리로 한 번에 가져오거나, userGroup 관계를 통해 확인하는 방식으로 변경하는 것이 좋습니다. 예를 들어, getStudyGroups의 결과를 받은 후 groupId 목록으로 userGroup에서 현재 사용자의 참여 정보를 한 번에 조회할 수 있습니다.
이러한 변경은 데이터베이스 부하를 크게 줄여줄 것입니다.
There was a problem hiding this comment.
제미나이봇을 추가했습니다~ 개지림~
There was a problem hiding this comment.
현재 각 스터디 그룹의 멤버가 최대 10명 정도로 제한되는 것으로 알고 있어서, 크게 DB에 부담이 되지는 않을 것 같습니다.
There was a problem hiding this comment.
또한, 현재 종료된 스터디 그룹에 대해서는 DB 조회를 무시하기 때문에 큰 병목 현상이 발생하지는 않을 것 같습니다.
| @IsString() | ||
| @IsOptional() | ||
| @Length(6, 6) | ||
| invitationCode?: string | null |
There was a problem hiding this comment.
invitationCode의 유효성 검사가 null 값을 허용하지 않는 것 같습니다. UpdateStudyDto에서 스터디를 비공개에서 공개로 전환하기 위해 invitationCode를 null로 설정하는 경우가 있을 수 있습니다. 현재 @IsString() 데코레이터 때문에 null 값을 보내면 유효성 검사에 실패하게 됩니다.
null 값을 허용하도록 유효성 검사를 수정하는 것을 제안합니다. class-validator의 ValidateIf를 사용하면 null이 아닐 경우에만 문자열 관련 유효성 검사를 수행하도록 할 수 있습니다. 또한 class-validator에서 ValidateIf를 import해야 합니다.
| @IsString() | |
| @IsOptional() | |
| @Length(6, 6) | |
| invitationCode?: string | null | |
| @IsOptional() | |
| @ValidateIf((o, value) => value !== null) | |
| @IsString() | |
| @Length(6, 6) | |
| invitationCode?: string | null |

Description
StudyGroupmain API의 기본적인 뼈대를 구현해보았습니다.우선
StudyGroup에서 활용할 schema를 추가하고 API를 구현했습니다.Additional context
Group모델에groupTag필드를 추가하였습니다.codedang/apps/backend/prisma/schema.prisma
Lines 138 to 162 in 3072118
해당 필드는 특정 스터디 그룹에서 진행하고 있는 문제들의 태그들의 합집합으로 이루어져 있으며,
별도의 필드 없이도 Group -> Problem -> ProblemTag -> Tag.name 를 통해 얻을 수는 있습니다.
다만 위와 같이 Tag의 이름을 찾을 경우 3번의 join 연산이 StudyGroup 조회 시 필요해 DB에 너무 많은 부담이 갈 것으로 예상됩니다.
따라서, 의도적으로
Group모델 내부에groupTag필드를 추가해 Group -> GroupTag -> Tag.name 를 통해 그룹에 속한 Tag 명을 찾을 수 있도록 하였습니다.현재로서는 StudyGroup에 속한 문제 리스트가 바뀔때 마다
GroupTag를 업데이트 하도록 하는 방식을 사용했습니다.StudyGroup을 수정하는
PATCH요청에 대해UseGroupLeaderGuard를 적용했습니다.codedang/apps/backend/apps/client/src/study/study.controller.ts
Lines 60 to 67 in 3072118
현재로서는 Group의 Leader가 아닌 일반 참여자들도 StudyGroup을 수정하는 것이 가능하게 해야 할지 정해진 것이 없어, 우선은 Leader만 이
StudyGroup을 수정 및 문제를 추가 및 제거할 수 있도록 하였습니다.Before submitting the PR, please make sure you do the following
fixes #123).