Skip to content

[Feat] 컬렉션 기본 CRUD API 구현 - #17

Merged
kangcheolung merged 3 commits into
developfrom
feature/16
Jul 15, 2026
Merged

[Feat] 컬렉션 기본 CRUD API 구현 #17
kangcheolung merged 3 commits into
developfrom
feature/16

Conversation

@kangcheolung

@kangcheolung kangcheolung commented Jul 15, 2026

Copy link
Copy Markdown
Member

🔍️작업 내용

✨ 상세 설명

구현 내용

  • POST /collections — 컬렉션 생성 (생성자가 owner로 설정, visibility 미입력 시 PRIVATE 기본값)
  • GET /collections/{id} — 컬렉션 단건 조회
  • POST /collections/{collectionId}/documents — 컬렉션에 문서 추가

구조

  • CollectionCommandService / CollectionQueryService (CQRS 분리)
  • CollectionConverter — Entity → DTO 변환
  • DocumentRepository — A담당자 documents 테이블 읽기 전용 참조용으로 추가
  • ErrorCode: COLLECTION_NOT_FOUND, DOCUMENT_NOT_FOUND, COLLECTION_DOCUMENT_ALREADY_EXISTS

참고

  • 엔티티(DocumentCollection, CollectionDocument)와 Flyway 마이그레이션(V7, V8)은 기존에 완료된 상태

🛠 추후 리팩토링 및 고도화 계획

  • POST /collections/{collectionId}/documents의 write 권한 체크가 현재 owner 여부만 확인함
    → 이슈 3 PermissionService.canWriteDocument() 완성 후 대체 예정 (코드에 TODO 마킹)

📸 스크린샷 (선택)

💬 리뷰 요구사항

  • DocumentRepository를 B담당자 쪽에서 추가한 것이 A담당자와 충돌 여지가 있는지 확인 부탁드립니다

Summary by CodeRabbit

  • 새로운 기능

    • 컬렉션을 생성하고 상세 정보를 조회할 수 있습니다.
    • 컬렉션에 문서를 추가할 수 있으며, 소유자 권한과 중복 추가를 검증합니다.
    • 상위 컬렉션, 설명, 공개 범위 및 상태 정보를 지원합니다.
    • 컬렉션과 포함 문서의 상세 정보가 응답으로 제공됩니다.
  • 버그 수정

    • 존재하지 않는 컬렉션이나 문서, 권한 부족 및 중복 문서 추가 상황에 대한 오류 처리를 추가했습니다.
  • 테스트

    • 컬렉션 생성, 조회, 문서 추가 및 주요 예외 상황에 대한 테스트를 추가했습니다.

kangcheolung and others added 2 commits July 15, 2026 15:44
- CollectionRepository, CollectionDocumentRepository, DocumentRepository(읽기 전용) 추가
- CollectionConverter, CollectionCommandService, CollectionQueryService 구현
- CollectionController: POST /collections, GET /collections/{id}, POST /collections/{collectionId}/documents
- ErrorCode: COLLECTION_NOT_FOUND, DOCUMENT_NOT_FOUND, COLLECTION_DOCUMENT_ALREADY_EXISTS 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- CollectionFixture: User, DocumentCollection, Document 팩토리 메서드
- CollectionQueryServiceTest: 정상 조회, COLLECTION_NOT_FOUND
- CollectionCommandServiceTest: 컬렉션 생성(정상/기본값/상위컬렉션/상위없음),
  문서 추가(정상/COLLECTION_NOT_FOUND/PERMISSION_DENIED/DOCUMENT_NOT_FOUND/중복)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kangcheolung, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 53 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 769e1bfa-bd86-4562-9551-5c7343993ab2

📥 Commits

Reviewing files that changed from the base of the PR and between e888a5b and 034611d.

📒 Files selected for processing (1)
  • src/test/java/com/opensource/docgrid/domain/collection/service/command/CollectionCommandServiceTest.java
📝 Walkthrough

Walkthrough

컬렉션 생성·단건 조회·문서 추가 REST API와 요청·응답 DTO, 저장소, 변환기, 서비스, 오류 코드 및 단위 테스트가 추가되었습니다.

Changes

컬렉션 API 기능

Layer / File(s) Summary
컬렉션 계약과 저장소
src/main/java/com/opensource/docgrid/domain/collection/dto/..., src/main/java/com/opensource/docgrid/domain/collection/repository/..., src/main/java/com/opensource/docgrid/domain/collection/converter/CollectionConverter.java, src/main/java/com/opensource/docgrid/domain/document/repository/DocumentRepository.java, src/main/java/com/opensource/docgrid/global/exception/ErrorCode.java
컬렉션 생성·문서 추가 요청과 응답 DTO, 엔티티 변환기, 컬렉션·문서 저장소 및 관련 오류 코드가 추가되었습니다.
생성 및 문서 추가 명령
src/main/java/com/opensource/docgrid/domain/collection/service/command/CollectionCommandService.java, src/test/java/com/opensource/docgrid/domain/collection/...
컬렉션 생성 시 부모 컬렉션, 기본 공개 범위, 초기 상태를 처리하고, 문서 추가 시 소유권·문서 존재·중복 여부를 검증합니다. 관련 성공 및 예외 시나리오가 테스트되었습니다.
조회 및 REST 엔드포인트
src/main/java/com/opensource/docgrid/domain/collection/service/query/CollectionQueryService.java, src/main/java/com/opensource/docgrid/domain/collection/controller/CollectionController.java, src/test/java/com/opensource/docgrid/domain/collection/service/query/CollectionQueryServiceTest.java
컬렉션 단건 조회 서비스와 POST /collections, GET /collections/{collectionId}, POST /collections/{collectionId}/documents 엔드포인트가 추가되었습니다.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CollectionController
  participant CollectionCommandService
  participant CollectionRepository
  participant DocumentRepository
  participant CollectionDocumentRepository
  CollectionController->>CollectionCommandService: 문서 추가 요청 전달
  CollectionCommandService->>CollectionRepository: 컬렉션 조회
  CollectionCommandService->>DocumentRepository: 문서 조회
  CollectionCommandService->>CollectionDocumentRepository: 중복 조합 확인
  CollectionCommandService->>CollectionDocumentRepository: 컬렉션 문서 저장
  CollectionCommandService-->>CollectionController: 문서 응답 반환
Loading

Possibly related PRs

  • DocGrid/backend#2: 공통 ApiResponse/ResponseUtils와 예외 인프라를 제공합니다.
  • DocGrid/backend#6: 컬렉션 엔티티와 데이터베이스 마이그레이션을 추가합니다.
  • DocGrid/backend#13: @CurrentUser 주입과 현재 사용자 보안 처리 흐름을 추가합니다.

Suggested labels: ✨ Feature

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.53% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 컬렉션 기본 CRUD API 구현이라는 핵심 변경을 짧고 명확하게 요약합니다.
Description check ✅ Passed 템플릿의 작업 내용, 상세 설명, 추후 계획, 리뷰 요구사항을 대부분 채워 변경 사항을 충분히 설명합니다.
Linked Issues check ✅ Passed #16의 저장소, 서비스, 컨트롤러, DTO, API, 에러 코드 요구사항이 모두 반영되어 있습니다.
Out of Scope Changes check ✅ Passed 테스트와 보조 fixture, 중복 추가 예외 코드는 기본 CRUD 구현을 뒷받침하는 범위 안에 있습니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/16

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (3)
src/main/java/com/opensource/docgrid/domain/collection/service/command/CollectionCommandService.java (1)

77-80: 🩺 Stability & Availability | 🔵 Trivial | 💤 Low value

유니크 제약 조건을 통한 동시성(TOCTOU) 방지 권장

현재 로직은 애플리케이션 레벨에서 문서가 컬렉션에 존재하는지 먼저 확인(existsBy...)한 후 저장(save)합니다. 동일한 사용자가 동시에 같은 문서를 추가하려고 시도할 경우, 두 요청이 거의 동시에 인입되어 둘 다 존재 여부 검사를 통과하고 중복 데이터가 저장되는 시간차 공격(TOCTOU) 위험이 발생할 수 있습니다.

데이터 무결성을 보장하기 위해 데이터베이스의 collection_documents 테이블 레벨에서 collection_iddocument_id 조합에 대해 유니크 인덱스(Unique Index)가 설정되어 있는지 확인하시기를 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/opensource/docgrid/domain/collection/service/command/CollectionCommandService.java`
around lines 77 - 80, Ensure the collection_documents database table has a
unique constraint or index on the collection_id and document_id combination,
using the schema or migration configuration for this entity. Keep the existing
CollectionCommandService existence check, and ensure duplicate-key violations
from concurrent saves are handled consistently with
COLLECTION_DOCUMENT_ALREADY_EXISTS.
src/main/java/com/opensource/docgrid/domain/collection/repository/CollectionDocumentRepository.java (1)

9-9: 🗄️ Data Integrity & Integration | 🔵 Trivial

데이터베이스 레벨의 유니크 제약조건 확인

애플리케이션 레벨에서 이 쿼리 메서드를 사용해 문서 중복 추가를 방지하고 있지만, 런타임 동시성 요청이 발생할 경우 경쟁 조건(Race Condition)으로 인해 exists 검증을 우회하여 중복 데이터가 삽입될 위험이 있습니다.

데이터 정합성을 확실히 보장하기 위해, 데이터베이스의 collection_documents (또는 관련 매핑 테이블)에 collection_iddocument_id를 묶는 유니크 인덱스(Unique Index)나 제약조건이 구성되어 있는지 함께 확인하시기를 권장합니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/main/java/com/opensource/docgrid/domain/collection/repository/CollectionDocumentRepository.java`
at line 9, Ensure the database schema for the collection_documents mapping table
enforces uniqueness on the combined collection_id and document_id columns, using
the project’s migration or entity configuration mechanism. Keep
existsByCollectionIdAndDocumentId for application-level checks, but add or
verify the composite unique index/constraint so concurrent requests cannot
insert duplicate mappings.
src/test/java/com/opensource/docgrid/domain/collection/service/command/CollectionCommandServiceTest.java (1)

73-73: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

ArgumentCaptor를 활용한 엔티티 상태 검증 고려

현재 save() 메서드에 전달되는 인자를 any(DocumentCollection.class)로 모킹하여 호출 여부만 검증하고 있습니다.

저장되는 엔티티에 이름, 설명, 소유자 등의 상태가 DTO로부터 의도한 대로 정확히 매핑되었는지 한 단계 더 정밀하게 확인하고 싶다면, ArgumentCaptor를 사용하여 캡처된 엔티티의 필드 값을 검증하는 방법을 고려해 볼 수 있습니다.

💡 ArgumentCaptor 적용 예시
import org.mockito.ArgumentCaptor;

// ...

ArgumentCaptor<DocumentCollection> captor = ArgumentCaptor.forClass(DocumentCollection.class);
then(collectionRepository).should().save(captor.capture());

DocumentCollection savedCollection = captor.getValue();
assertThat(savedCollection.getName()).isEqualTo(request.name());
// 필요한 필드 추가 검증...
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/test/java/com/opensource/docgrid/domain/collection/service/command/CollectionCommandServiceTest.java`
at line 73, Update the test around the collection command service save
verification to capture the DocumentCollection passed to
collectionRepository.save(...) with an ArgumentCaptor, then assert that its
mapped fields such as name, description, and owner match the request DTO.
Preserve the existing save invocation verification while adding precise
entity-state assertions.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In
`@src/main/java/com/opensource/docgrid/domain/collection/repository/CollectionDocumentRepository.java`:
- Line 9: Ensure the database schema for the collection_documents mapping table
enforces uniqueness on the combined collection_id and document_id columns, using
the project’s migration or entity configuration mechanism. Keep
existsByCollectionIdAndDocumentId for application-level checks, but add or
verify the composite unique index/constraint so concurrent requests cannot
insert duplicate mappings.

In
`@src/main/java/com/opensource/docgrid/domain/collection/service/command/CollectionCommandService.java`:
- Around line 77-80: Ensure the collection_documents database table has a unique
constraint or index on the collection_id and document_id combination, using the
schema or migration configuration for this entity. Keep the existing
CollectionCommandService existence check, and ensure duplicate-key violations
from concurrent saves are handled consistently with
COLLECTION_DOCUMENT_ALREADY_EXISTS.

In
`@src/test/java/com/opensource/docgrid/domain/collection/service/command/CollectionCommandServiceTest.java`:
- Line 73: Update the test around the collection command service save
verification to capture the DocumentCollection passed to
collectionRepository.save(...) with an ArgumentCaptor, then assert that its
mapped fields such as name, description, and owner match the request DTO.
Preserve the existing save invocation verification while adding precise
entity-state assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a5759218-3647-47da-ae9a-d666cccceb33

📥 Commits

Reviewing files that changed from the base of the PR and between 78a2ed2 and e888a5b.

📒 Files selected for processing (15)
  • src/main/java/com/opensource/docgrid/domain/collection/controller/CollectionController.java
  • src/main/java/com/opensource/docgrid/domain/collection/converter/CollectionConverter.java
  • src/main/java/com/opensource/docgrid/domain/collection/dto/request/AddDocumentRequest.java
  • src/main/java/com/opensource/docgrid/domain/collection/dto/request/CreateCollectionRequest.java
  • src/main/java/com/opensource/docgrid/domain/collection/dto/response/CollectionDocumentResponse.java
  • src/main/java/com/opensource/docgrid/domain/collection/dto/response/CollectionResponse.java
  • src/main/java/com/opensource/docgrid/domain/collection/repository/CollectionDocumentRepository.java
  • src/main/java/com/opensource/docgrid/domain/collection/repository/CollectionRepository.java
  • src/main/java/com/opensource/docgrid/domain/collection/service/command/CollectionCommandService.java
  • src/main/java/com/opensource/docgrid/domain/collection/service/query/CollectionQueryService.java
  • src/main/java/com/opensource/docgrid/domain/document/repository/DocumentRepository.java
  • src/main/java/com/opensource/docgrid/global/exception/ErrorCode.java
  • src/test/java/com/opensource/docgrid/domain/collection/fixture/CollectionFixture.java
  • src/test/java/com/opensource/docgrid/domain/collection/service/command/CollectionCommandServiceTest.java
  • src/test/java/com/opensource/docgrid/domain/collection/service/query/CollectionQueryServiceTest.java

저장되는 엔티티의 name, description, owner 필드가 요청 DTO와 일치하는지 검증

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@kangcheolung
kangcheolung merged commit 27599cc into develop Jul 15, 2026
1 check passed
@kangcheolung kangcheolung added the ✨ Feature 기능 개발 label Jul 15, 2026
@kangcheolung kangcheolung self-assigned this Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 기능 개발

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 컬렉션 기본 CRUD API 구현

1 participant