Conversation
- 기존 토큰에서 member_id를 받아 memberOrg가 존재하는지 확인하는 형태에서, MemberOrgId를 헤더에서 추출해 해당 id로 MemberOrg를 반환하는 방식으로 수정했습니다. - ApiResponse 객체를 만들어 controller에서 공통 형태로 response 반환을 할 수 있도록 했습니다. 현재는 성공했을 경우에 대한 반환 처리만 되어 있어 추후 exception 관련해서도 처리를 해야합니다. - 기존의 Event 폴더 밑에 있던 EventParticipantDto를 member 폴더 밑의 SimpleMemberProfileDto로 변경했습니다. 투표 등 타 도메인에서도 동일한 DTO를 사용하기에 중복 제거를 위해 변경했습니다. - 기존에 EventService에 있던 validateExecutive 등 활동 회원 멤버/운영진 여부 체크 메서드를 MemberOrgValidator 파일로 분리했습니다. 투표 혹은 게시글에서도 해당 기능을 공통적으로 활용해 권한 체크할 예정입니다.
- 다중 투표가 가능함에 따라 PollParticipant - Vote 형식으로 테이블을 나누어 구현했습니다. PollParticipant는 투표 참여 여부만을 관리하고 Vote에서 투표 내용을 관리합니다. - PollTarget은 전체 참여 투표가 아니라 일부 참여일 때 참석 대상자를 관리하는 테이블입니다.
- 구현할 poll 관련 API의 DTO를 구현했습니다.
1. 구현된 API 경로
- 투표 생성: POST /api/polls
- 투표 삭제: DELETE /api/polls/{pollId}
- 투표 수정: PATCH /api/polls/{pollId}
- 투표 상세 조회: GET /api/polls/{pollId}
- 월간 투표 조회: GET /api/polls/monthly?orgId=3&year=2025&month=12
- 캘린더 화면 사이드바 투표(마감임박/진행중) 조회: GET /api/polls/active?orgId=3
- 투표하기(투표/재투표/투표취소): POST /api/polls/{pollId}/vote
Summary of ChangesHello @tishakong, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request significantly refactors the user and organization management system, introducing a robust multi-profile architecture. It also integrates new calendar and polling features to enhance collaborative functionalities within different organizations. The changes aim to provide a more flexible and scalable foundation for user interactions and content management. Highlights
Changelog
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request introduces a significant refactoring to support a multi-profile and multi-organization system. Key changes include the introduction of ActiveProfile and ProfileContext for handling organization-specific contexts via HTTP headers, and a new MemberOrg entity to manage member details (like nickname, role, type, and profile image) within specific organizations. The Member entity is simplified to hold only core user account information, with its status field renamed to accountStatus for clarity and consistency. Consequently, many existing services, controllers, and repositories across free, QnA, and tip boards, as well as admin and notification modules, have been updated to utilize the new MemberOrg entity and ProfileContext for operations like post creation, retrieval, and reporting. The old MemberRepository and several board-specific member repositories have been replaced or refactored. Additionally, new entities and services for event and poll management (Event, EventParticipant, Poll, PollOption, PollParticipant, PollTarget, Vote) have been added, all integrating with the new multi-profile structure. Several initializers and admin dashboard features have been commented out or removed, indicating ongoing development or temporary deactivation. Review comments highlight the need to consolidate redundant status fields in the Member entity, enforce uniqueness constraints on Organization names at the database level to prevent race conditions, and validate participant IDs when creating partial scope polls to ensure they are valid and belong to the correct organization.
| private AccountStatus status; | ||
|
|
||
| private Status status; | ||
| private LocalDateTime createdAt = LocalDateTime.now(); | ||
|
|
||
| private AccountStatus accountStatus; // 탈퇴 계정을 위해 |
There was a problem hiding this comment.
There are two status fields in the Member entity: status and accountStatus. This is redundant and can lead to bugs. For example, deactivate() updates accountStatus, but repository methods like findByStatus will query against the status field.
Please consolidate this into a single field, for example accountStatus, and use it consistently across the application. You will also need to update other parts of the code that reference the removed field, such as CommonDataInitializer and repository methods.
There was a problem hiding this comment.
accountStatus : soft/hard delete를 위해 존재(ex. 신고로 인한 게시글 비활성화 및 탈퇴 회원 관리 등)
orgStatus : 해당 조직에 허용/반려되었는지 확인하기 위해 존재
현재 제 코드에서도 Member 엔티티에 accountStatus가 중복된 점 확인했습니다
운영진 API PR 올릴 때 해당 문제 반영하겠습니다 !
| @Entity | ||
| @Getter | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Builder | ||
| public class Organization { |
There was a problem hiding this comment.
The Organization entity lacks a unique constraint on its name. While the service layer checks for duplicates before creating a new organization, this is not sufficient to prevent race conditions that could lead to duplicate entries. It's best practice to enforce this uniqueness at the database level.
I recommend adding a @Table(uniqueConstraints = ...) annotation. For CLUB type, the constraint should probably be on (name, school_id). For COMMUNITY, it could be on name.
There was a problem hiding this comment.
서비스 계층에서 동아리/소모임 이름 중복을 확인해도 동시성 문제가 발생할 수 있으니,
엔티티 내에서 @Table 어노테이션으로 제약 조건 설정하라는 문제인 것 같아요 !
해당 부분도 리팩토링 때 반영하면 좋을 것 같습니다
| if (reqDto.getVoteScope() == PollScope.PARTIAL) { | ||
| //TODO events에 있는 리스트에 있는 인원이 멤버가 맞는지 검증하는 로직을 공통으로 빼내서 검증 로직 추가 | ||
| List<Long> targets = reqDto.getParticipants().stream().distinct().toList(); | ||
| for (Long targetId : targets) { | ||
| pollTargetRepository.save(PollTarget.builder() | ||
| .poll(poll) | ||
| .memberOrgId(targetId) | ||
| .build()); | ||
| } | ||
| } |
There was a problem hiding this comment.
When creating a poll with PollScope.PARTIAL, the provided participant IDs are not validated. This could lead to PollTarget entries being created for non-existent MemberOrg IDs or for members who do not belong to the poll's organization.
You should add validation to ensure all participant IDs are valid and belong to the correct organization before creating PollTarget records. You can look at EventService.addParticipants for an example of how to implement this.
이슈 번호
작업 내용