Skip to content

[FEAT] 프로젝트 목록에 keyword 검색과 sort=name 정렬 추가 - #452

Merged
jongjunn merged 2 commits into
developfrom
feat/mnppi-project-search
Aug 13, 2026
Merged

[FEAT] 프로젝트 목록에 keyword 검색과 sort=name 정렬 추가#452
jongjunn merged 2 commits into
developfrom
feat/mnppi-project-search

Conversation

@MNPPI223

@MNPPI223 MNPPI223 commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

📌 연관 이슈


📝 작업 내용

  • 프로젝트 목록 조회(GET /api/projects)에 keyword 파라미터 추가 — 프로젝트명 대소문자 무시 부분일치 검색
  • sort 화이트리스트에 name 추가 (기존 dueDate·createdAt과 동일하게 지원)
  • 도메인 계약(ProjectRepository)부터 영속성 어댑터까지 5개 계층 전부 반영, 페이지네이션은 기존 count 쿼리 재사용 구조라 별도 변경 없음

🖥️ 프론트엔드 연동 가이드 (API 명세)

1. 주요 엔드포인트

  • GET /api/projects : 프로젝트 목록 조회 (기존 엔드포인트, 파라미터만 확장)

2. 요청 파라미터 (Request)

파라미터명 위치 필수 여부 설명
keyword Query 선택 프로젝트명 대소문자 무시 부분일치 검색. 미전달 시 필터 없음
sort Query 선택 dueDate | createdAt | name. 그 외 값은 기본값(createdAt)으로 조용히 대체(400 아님)
order Query 선택 asc | desc, 기본 desc
status Query 선택 기존과 동일
page / size Query 선택 기존과 동일

3. 정상 응답 예시 (200 OK)

응답 JSON 보기 (클릭)
{
  "data": {
    "content": [
      {
        "id": 1,
        "tag": "ZBRA",
        "color": "#059669",
        "name": "Zebra Groupware",
        "description": "설명",
        "status": "TODO",
        "startDate": "2026-01-01",
        "dueDate": "2026-12-31",
        "teamCount": 0,
        "actionCount": 0,
        "completedActionCount": 0,
        "meetingCount": 0,
        "progressPct": 0.0,
        "teamNames": []
      }
    ],
    "page": 0,
    "size": 20,
    "totalElements": 1,
    "totalPages": 1,
    "hasNext": false
  },
  "httpStatus": 200,
  "message": "프로젝트 목록을 조회했습니다."
}

4. ⚠️ 프론트엔드 참고 및 주의사항

  • sort=name을 안 보내던 기존 요청은 동작 그대로다 — 이번 변경은 파라미터 추가만, 기존 계약은 안 건드림
  • keyword는 이름 필드만 검색 대상이다(설명·태그는 검색 안 됨)

🚨 주요 에러 코드 및 예외 (Exceptions)

  • 없음 — 기존 필터/정렬과 동일하게 잘못된 값은 400이 아니라 조용히 기본값으로 대체됨(기존 정책 유지)

💡 백엔드 리뷰 포인트 (Backend Review)

  • 아키텍처 및 도메인: keyword가 도메인 계약(ProjectRepository)부터 프레젠테이션까지 5계층 전부에 흘러가는지, content 쿼리와 count 쿼리가 항상 같은 Specification을 쓰는 기존 원칙이 keyword 조건에도 유지됐는지 확인 부탁
  • 우려되는 부분이나 고민: ProjectService.getOwnerDashboardSummary(대시보드 KPI)가 같은 countByCompanyId를 호출하고 있어서 이번 시그니처 변경에 딸려 함께 수정됐다 — 원래 이슈 범위 밖이지만 컴파일이 걸려서 불가피했음. 이 부분만 별도로 봐주시면 좋겠음

✅ 체크리스트

  • 코드 컨벤션을 준수했습니다.
  • 불필요한 주석 및 콘솔 로그를 제거했습니다.
  • API 기능이 정상 동작하는지 테스트했습니다. (실제 HTTP 요청으로 검증 완료)
  • 예외(잘못된 값) 상황에 대한 검증 및 테스트를 통과했습니다.

Summary by CodeRabbit

  • 새 기능

    • 프로젝트 목록에서 프로젝트명 키워드로 부분 일치 검색을 지원합니다.
    • 검색은 대소문자를 구분하지 않으며, 검색어가 없으면 전체 목록을 조회합니다.
    • 프로젝트명 기준 정렬 옵션이 추가되었습니다.
    • 검색 결과에 맞춰 전체 건수와 페이지네이션이 반영됩니다.
  • 개선 사항

    • 상태 필터, 정렬 및 페이지네이션과 키워드 검색을 함께 사용할 수 있습니다.
    • 프로젝트 목록 조회 관련 검증을 강화했습니다.

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bf4eec4a-faec-4658-aecf-7dd891ab5b9e

📥 Commits

Reviewing files that changed from the base of the PR and between 9bd9c01 and c908195.

📒 Files selected for processing (3)
  • src/main/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapter.java
  • src/test/java/com/module06/backend/project/application/service/ProjectServiceTest.java
  • src/test/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapterListFilterTest.java
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/test/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapterListFilterTest.java
  • src/main/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapter.java

📝 Walkthrough

Walkthrough

프로젝트 목록 조회에 keyword 검색과 name 정렬을 추가했습니다. 검색 조건은 목록과 전체 건수 조회에 동일하게 적용됩니다. 관련 계약, 구현, 호출부 및 테스트를 갱신했습니다.

Changes

프로젝트 목록 검색 및 정렬

Layer / File(s) Summary
목록 조회 계약과 호출 흐름
src/main/java/com/module06/backend/project/application/usecase/GetProjectListUseCase.java, src/main/java/com/module06/backend/project/domain/repository/ProjectRepository.java, src/main/java/com/module06/backend/project/presentation/api/ProjectController.java, src/main/java/com/module06/backend/project/application/service/ProjectService.java
목록 조회 계약과 호출에 선택적 keyword를 추가했습니다. keyword가 없으면 필터를 적용하지 않습니다. 대시보드의 전체 프로젝트 수 조회는 null 필터를 전달합니다.
키워드 조건과 정렬 구현
src/main/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapter.java
프로젝트 이름에 대소문자를 구분하지 않는 부분 일치 조건을 추가했습니다. 목록과 건수 조회에 같은 조건을 적용합니다. name 정렬을 허용합니다.
목록 조회 검증
src/test/java/com/module06/backend/project/application/service/ProjectServiceTest.java, src/test/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapterListFilterTest.java, src/test/java/com/module06/backend/project/presentation/api/ProjectControllerTest.java
keyword 전달, 상태 필터, 건수 조회, dueDate 정렬, name 정렬 및 대소문자 무시 검색을 검증합니다.

Estimated code review effort: 2 (Simple) | ~10 minutes

Mergeability Score: ⚪ Minimal · up to c9081

This change adds project-name keyword filtering and name sorting while preserving existing list behavior; no actionable merge-blocking risk remains beyond normal checks and review.

Sequence Diagram(s)

sequenceDiagram
  participant ProjectController
  participant GetProjectListUseCase
  participant ProjectService
  participant ProjectPersistenceAdapter
  ProjectController->>GetProjectListUseCase: keyword와 목록 조건 전달
  GetProjectListUseCase->>ProjectService: 목록 조회 실행
  ProjectService->>ProjectPersistenceAdapter: keyword 포함 목록 및 건수 조회
  ProjectPersistenceAdapter-->>ProjectService: 검색 결과와 전체 건수 반환
  ProjectService-->>ProjectController: 프로젝트 목록 응답 반환
Loading

Possibly related PRs

  • Z-Groupware/BACKEND#29: ProjectServiceGetProjectListUseCase의 프로젝트 목록 메서드를 변경합니다.
  • Z-Groupware/BACKEND#253: 프로젝트 목록 서비스, 유스케이스, 저장소 어댑터 및 테스트를 함께 변경합니다.
  • Z-Groupware/BACKEND#305: 동일한 프로젝트 목록 메서드에 필터링 인자를 확장합니다.

Suggested reviewers: mosungjin

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 프로젝트 목록의 keyword 검색과 sort=name 정렬 추가라는 주요 변경 사항을 정확히 요약합니다.
Linked Issues check ✅ Passed [직접 연결 이슈 #450] keyword 검색, sort=name 정렬, 기존 정렬 회귀 방지 요구사항을 모두 반영했습니다.
Out of Scope Changes check ✅ Passed 변경 사항은 연결 이슈의 검색·정렬 기능과 관련 계층 및 회귀 테스트 범위에 포함됩니다.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/mnppi-project-search

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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/test/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapterListFilterTest.java (1)

72-83: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

검색 결과의 프로젝트명을 검증하세요.

현재 검증은 결과 수와 count만 확인합니다. 잘못된 조건이 임의의 두 프로젝트를 반환해도 이 테스트는 통과할 수 있습니다. 두 Zebra 프로젝트가 반환되고 Other Project가 제외되는지 검증하세요.

검증 강화 예시
         assertThat(result).hasSize(2);
+        assertThat(result)
+                .extracting(Project::getName)
+                .containsExactlyInAnyOrder(
+                        "프로젝트 Zebra Groupware",
+                        "프로젝트 zebra internal tools");
         assertThat(projectRepository.countByCompanyId(COMPANY, "ZEBRA", null)).isEqualTo(2L);
🤖 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/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapterListFilterTest.java`
around lines 72 - 83, Strengthen filtersByKeywordCaseInsensitive by asserting
the returned projects’ names, verifying both “Zebra Groupware” and “zebra
internal tools” are present and “Other Project” is excluded, while retaining the
existing size and count assertions.
src/test/java/com/module06/backend/project/application/service/ProjectServiceTest.java (1)

164-172: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

keyword 전달을 비어 있지 않은 값으로 검증하세요.

현재 목록 테스트는 모두 keyword = null만 사용합니다. 따라서 ProjectService.list가 비어 있지 않은 keyword를 목록 조회와 count 조회에 동일하게 전달하는지 검증하지 못합니다.

검증 테스트 예시
+@Test
+void listPassesKeywordToContentAndCountQueries() {
+    // 기존 목록 조회 의존성 스텁 설정
+
+    projectService.list(COMPANY, "zebra", null, null, "desc", 0, 20);
+
+    verify(projectRepository).findAllByCompanyId(
+            COMPANY, "zebra", null, null, "desc", 0, 20);
+    verify(projectRepository).countByCompanyId(COMPANY, "zebra", null);
+}

PR 목표는 서비스 계층의 keyword 전달 검증을 요구합니다.

Also applies to: 186-193

🤖 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/module06/backend/project/application/service/ProjectServiceTest.java`
around lines 164 - 172, Update the project list tests around ProjectServiceTest
to use a non-empty keyword when calling ProjectService.list, and stub/verify
that the same keyword is passed to both projectRepository.findAllByCompanyId and
projectRepository.countByCompanyId. Apply this to the related test at the
additional location as well, preserving the existing assertions and other
filters.
🤖 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.

Inline comments:
In
`@src/main/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapter.java`:
- Around line 122-123: Update the keyword normalization in the predicate
construction to use Locale.ROOT with keyword.toLowerCase, and add a regression
test covering Turkish JVM locale behavior to verify matching remains consistent
with cb.lower(root.get("name")).

---

Nitpick comments:
In
`@src/test/java/com/module06/backend/project/application/service/ProjectServiceTest.java`:
- Around line 164-172: Update the project list tests around ProjectServiceTest
to use a non-empty keyword when calling ProjectService.list, and stub/verify
that the same keyword is passed to both projectRepository.findAllByCompanyId and
projectRepository.countByCompanyId. Apply this to the related test at the
additional location as well, preserving the existing assertions and other
filters.

In
`@src/test/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapterListFilterTest.java`:
- Around line 72-83: Strengthen filtersByKeywordCaseInsensitive by asserting the
returned projects’ names, verifying both “Zebra Groupware” and “zebra internal
tools” are present and “Other Project” is excluded, while retaining the existing
size and count assertions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 4d1cb8ca-616c-465a-8007-2dedcc9e02f3

📥 Commits

Reviewing files that changed from the base of the PR and between 317dab1 and 9bd9c01.

📒 Files selected for processing (8)
  • src/main/java/com/module06/backend/project/application/service/ProjectService.java
  • src/main/java/com/module06/backend/project/application/usecase/GetProjectListUseCase.java
  • src/main/java/com/module06/backend/project/domain/repository/ProjectRepository.java
  • src/main/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapter.java
  • src/main/java/com/module06/backend/project/presentation/api/ProjectController.java
  • src/test/java/com/module06/backend/project/application/service/ProjectServiceTest.java
  • src/test/java/com/module06/backend/project/infrastructure/persistence/ProjectPersistenceAdapterListFilterTest.java
  • src/test/java/com/module06/backend/project/presentation/api/ProjectControllerTest.java

@MNPPI223 MNPPI223 self-assigned this Aug 13, 2026
@MNPPI223 MNPPI223 added the enhancement New feature or request label Aug 13, 2026
@MNPPI223 MNPPI223 added this to Z Aug 13, 2026
@github-project-automation github-project-automation Bot moved this to Todo in Z Aug 13, 2026
- toLowerCase()에 Locale.ROOT 명시(터키어 등 로케일 의존 대소문자 변환 방지)
- 키워드 검색 테스트가 결과 개수뿐 아니라 실제 프로젝트명까지 검증하도록 강화
- 서비스 계층이 비어있지 않은 keyword를 목록·count 조회에 동일하게 전달하는지 검증하는 테스트 추가

PR #452
@jongjunn
jongjunn merged commit 753b996 into develop Aug 13, 2026
15 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Z Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[FEAT] 프로젝트 목록 keyword 검색 + sort=name 정렬 추가

2 participants