-
Notifications
You must be signed in to change notification settings - Fork 2
feat: OOO에서 작성한 글 기능 구현 #2138
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
feat: OOO에서 작성한 글 기능 구현 #2138
Conversation
* 분실물 게시글 작성자의 단체 정보를 관리하기 위한 organizations 테이블 및 엔티티 추가
* is_council 대신 organization 객체로 단체 정보 제공
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
This PR implements organization-authored articles functionality, allowing organizations (like student councils) to post articles and be identified as such. The change introduces a new organizations table to store organization metadata and adds a V2 endpoint for lost item articles that includes organization information.
Changes:
- Added
organizationstable to store organization details (name and location) linked to user accounts - Created
Organizationentity and repository for database operations - Implemented
getLostItemArticleV2service method that queries organization data - Added
LostItemArticleResponseV2DTO with embedded organization information - Exposed new V2 endpoint
/lost-item/v2/{id}that returns organization details for organizational authors
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| V228__add_organizations_table.sql | Database migration creating the organizations table with user_id, name, location, and soft-delete fields |
| OrganizationRepository.java | Repository interface for querying organizations by user ID |
| Organization.java | JPA entity representing organization data |
| LostItemArticleService.java | Service layer enhanced with V2 method that fetches organization info for article authors |
| LostItemArticleResponseV2.java | Response DTO including nested organization details when present |
| LostItemArticleController.java | Controller exposing the new V2 endpoint |
| LostItemArticleApi.java | API documentation for the V2 endpoint |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The created_at and updated_at columns should be removed from this migration. Since the Organization entity extends BaseEntity, these timestamp fields are automatically managed by JPA's auditing mechanism. Including them in the SQL migration will cause conflicts with JPA's entity mappings and create duplicate column definitions.
| `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | |
| `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, |
| private String location; | ||
|
|
||
| @NotNull | ||
| @Column(name = "is_deleted", nullable = false) |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The is_deleted column definition in the SQL migration uses TINYINT(1) which is the standard for boolean columns in this codebase. However, the corresponding entity field uses Boolean type without the columnDefinition attribute. For consistency with other entities in the codebase (like KoinNotice, Club, ClubQna), add a columnDefinition attribute to ensure proper mapping: @Column(name = "is_deleted", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0")
| @Column(name = "is_deleted", nullable = false) | |
| @Column(name = "is_deleted", nullable = false, columnDefinition = "TINYINT(1) DEFAULT 0") |
|
|
||
| @NotNull | ||
| @Column(name = "is_deleted", nullable = false) | ||
| private Boolean isDeleted = false; |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency with other entities in the codebase that use boolean fields (such as KoinNotice, Club), consider using the static import import static java.lang.Boolean.FALSE; and initializing the field as private Boolean isDeleted = FALSE; instead of false. This follows the established pattern in the project.
| @@ -0,0 +1,16 @@ | |||
| -- organizations 테이블 생성 (단체 정보 관리) | |||
| CREATE TABLE `organizations` ( | |||
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The table creation should include the schema prefix for consistency with other recent migrations in the codebase. Recent migrations (V194, V222, V226) consistently use CREATE TABLE IF NOT EXISTS \koin`.`table_name`pattern. Update the statement to:CREATE TABLE IF NOT EXISTS `koin`.`organizations``
| CREATE TABLE `organizations` ( | |
| CREATE TABLE IF NOT EXISTS `koin`.`organizations` ( |
| -- organizations 테이블 생성 (단체 정보 관리) | ||
| CREATE TABLE `organizations` ( | ||
| `id` INT NOT NULL AUTO_INCREMENT, | ||
| `user_id` INT NOT NULL COMMENT '단체 계정 user_id', |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user_id column uses INT instead of INT UNSIGNED. Since this column references the users table's id column (which is typically INT UNSIGNED in this codebase), it should match that type for proper foreign key compatibility. Use INT UNSIGNED NOT NULL COMMENT '단체 계정 user_id'
| `user_id` INT NOT NULL COMMENT '단체 계정 user_id', | |
| `user_id` INT UNSIGNED NOT NULL COMMENT '단체 계정 user_id', |
| public LostItemArticleResponseV2 getLostItemArticleV2(Integer articleId, Integer userId) { | ||
| Article article = articleRepository.getById(articleId); | ||
| setPrevNextArticle(LOST_ITEM_BOARD_ID, article); | ||
|
|
||
| LostItemArticle lostItemArticle = article.getLostItemArticle(); | ||
| User author = lostItemArticle.getAuthor(); | ||
|
|
||
| boolean isMine = author != null && Objects.equals(author.getId(), userId); | ||
|
|
||
| Organization organization = null; | ||
| if (author != null) { | ||
| organization = organizationRepository | ||
| .findByUserIdAndIsDeletedFalse(author.getId()) | ||
| .orElse(null); | ||
| } | ||
|
|
||
| return LostItemArticleResponseV2.of(article, isMine, organization); | ||
| } |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The new getLostItemArticleV2 method lacks test coverage. Given that the codebase has test infrastructure in place (as evidenced by LostItemChatRoomInfoServiceTest and fixtures), unit tests should be added to verify the organization lookup behavior, including scenarios where:
- An article is authored by a user with an associated organization
- An article is authored by a user without an organization (null case)
- An article is authored by a deleted/null user
| import lombok.NoArgsConstructor; | ||
|
|
||
| @Getter | ||
| @Entity | ||
| @Table(name = "organizations") | ||
| @NoArgsConstructor(access = AccessLevel.PROTECTED) |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Organization entity has an is_deleted field but is missing the @Where(clause = "is_deleted=0") annotation that is consistently used across the codebase for soft-delete functionality. This annotation ensures that deleted entities are automatically filtered out from queries by default. For consistency with other entities (like Article, KoinNotice, User, etc.), add this annotation to the class level.
| import lombok.NoArgsConstructor; | |
| @Getter | |
| @Entity | |
| @Table(name = "organizations") | |
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | |
| import lombok.NoArgsConstructor; | |
| import org.hibernate.annotations.Where; | |
| @Getter | |
| @Entity | |
| @Table(name = "organizations") | |
| @NoArgsConstructor(access = AccessLevel.PROTECTED) | |
| @Where(clause = "is_deleted=0") |
| `created_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||
| `updated_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, | ||
| PRIMARY KEY (`id`), | ||
| UNIQUE KEY `uk_organizations_user_id` (`user_id`) |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The user_id column references a user but does not include a FOREIGN KEY constraint. Based on the codebase patterns (e.g., V100, V152, V204), columns that reference other tables should include explicit foreign key constraints. Consider adding: CONSTRAINT fk_organizations_user_id FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE or ON DELETE SET NULL depending on the desired behavior when a user is deleted.
| UNIQUE KEY `uk_organizations_user_id` (`user_id`) | |
| UNIQUE KEY `uk_organizations_user_id` (`user_id`), | |
| CONSTRAINT `fk_organizations_user_id` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE |
| @@ -0,0 +1,16 @@ | |||
| -- organizations 테이블 생성 (단체 정보 관리) | |||
| CREATE TABLE `organizations` ( | |||
| `id` INT NOT NULL AUTO_INCREMENT, | |||
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The id column uses INT instead of INT UNSIGNED which is the standard in recent migrations (V140+). For consistency with the codebase and to allow for a larger range of positive IDs, use INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '고유 ID'
| `id` INT NOT NULL AUTO_INCREMENT, | |
| `id` INT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '고유 ID', |
| return ResponseEntity.ok().body(lostItemArticleService.getLostItemArticle(articleId, userId)); | ||
| } | ||
|
|
||
| @GetMapping("/lost-item/v2/{id}") |
Copilot
AI
Jan 19, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method overrides LostItemArticleApi.getLostItemArticleV2; it is advisable to add an Override annotation.
| @GetMapping("/lost-item/v2/{id}") | |
| @GetMapping("/lost-item/v2/{id}") | |
| @Override |
🔍 개요
🚀 주요 변경 내용
💬 참고 사항
✅ Checklist (완료 조건)