Skip to content

[FEATURE] 리뷰 조회, 알바 검색 필터링 조건 추가#68

Merged
codie0226 merged 1 commit intoUMC-AlbaLog:mainfrom
ChangSik88:feat/ALBA_60
Feb 17, 2026
Merged

[FEATURE] 리뷰 조회, 알바 검색 필터링 조건 추가#68
codie0226 merged 1 commit intoUMC-AlbaLog:mainfrom
ChangSik88:feat/ALBA_60

Conversation

@ChangSik88
Copy link
Copy Markdown
Contributor

@ChangSik88 ChangSik88 commented Feb 14, 2026


name: PR 템플릿
about: PR 생성 시 이 템플릿을 사용해 주세요.
title: "[PR] "

#️⃣ 연관된 이슈

관련된 이슈 번호를 적어주세요. 예: #이슈번호
closes #67

#️⃣ 작업 내용

이번 PR에서 작업한 내용을 간략히 설명해주세요. (이미지 첨부 가능)

  1. 스토어 리뷰 조회
  • store_review : Get api/store/review/{storeId}
    쿼리 파라미터의 storeId를 통해 특정 가게의 모든 리뷰를 불러올 수 있음. 리뷰 생성시에 가져오는 응답과 형식 자체는 같고 리스트를 가져오는 것만 변했음
스크린샷 2026-02-14 232820
  1. 대타 아르바이트 검색 시 필터링 조건 추가
  • search_alba
    기존 아르바이트 검색 기능은 유저 인증을 하지 않고 지원된 아르바이트라도 날짜 조건만 맞다면 모두 가져왔음.
    개선된 기능은 만약 유저가 로그인을 한 상태라면 이미 지원했던 아르바이트는 검색 시 나타나지 않게 하였음. 이를 통해 불필요한 공고를 지워냄으로서 UI 개선
스크린샷 2026-02-14 232848

#️⃣ 테스트 결과

코드 변경에 대해 테스트를 수행한 결과를 요약해주세요. 예: 모든 테스트 통과 여부, 새로 작성한 테스트 케이스 등

swagger UI 및 로컬 테스트 성공

#️⃣ 변경 사항 체크리스트

  • 코드에 영향이 있는 모든 부분에 대한 테스트를 작성하고 실행했나요?
  • 문서를 작성하거나 수정했나요? (필요한 경우)
  • 코드 컨벤션에 따라 코드를 작성했나요?
  • 본 PR에서 발생할 수 있는 모든 의존성 문제가 해결되었나요?

#️⃣ 스크린샷 (선택)

관련된 스크린샷이 있다면 여기에 첨부해주세요.

#️⃣ 리뷰 요구사항 (선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요.
예시: 이 부분의 코드가 잘 작동하는지 테스트해 주실 수 있나요?

📎 참고 자료 (선택)

관련 문서, 스크린샷, 또는 예시 등이 있다면 여기에 첨부해주세요

Summary by CodeRabbit

Release Notes

  • New Features
    • Added endpoint to retrieve store reviews with user and store details.
    • Implemented personalized search result filtering for authenticated users.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Feb 14, 2026

Walkthrough

Adds store review retrieval functionality via a new controller endpoint, service layer, and repository query. Enhances alba search with JWT authentication and filters out postings the authenticated user has already applied to by propagating user UUID as a buffer through the call stack.

Changes

Cohort / File(s) Summary
Store Review Feature
src/DTO/store_review_dto.ts, src/service/store_review_service.ts, src/repository/store_review_repository.ts, src/controller/store_review_controller.ts
New store review query feature: adds DTO interface, repository function to fetch reviews by store ID (with related user/store data), service layer to transform results into StoreReviewDto shape, and GET endpoint on controller to expose the functionality.
Alba Search User Filtering
src/controller/search_alba_controller.ts, src/service/search_alba_service.ts, src/repository/search_alba_repository.ts
Adds JWT protection via @Security('jwt') to search endpoint, extracts authenticated user's UUID from request, converts to Buffer, and propagates through service/repository layers. Repository applies conditional filter to exclude postings where user has already applied (user_alba none clause).

Sequence Diagram(s)

sequenceDiagram
    actor User
    participant Controller as Search Alba<br/>Controller
    participant Service as Search Alba<br/>Service
    participant Repo as Search Alba<br/>Repository
    participant DB as Database

    User->>Controller: GET /search (JWT token)
    Controller->>Controller: `@Security`('jwt') validates<br/>Extracts req.user.id
    Controller->>Controller: Convert UUID to Buffer<br/>(userBuffer)
    Controller->>Service: getFilteredAlba(params, userBuffer)
    Service->>Repo: findPostingByFilter({...params, userBuffer})
    Repo->>Repo: Apply filter: user_alba none<br/>(exclude user's applications)
    Repo->>DB: Query with exclusion filter
    DB-->>Repo: Alba postings (excluding user's)
    Repo-->>Service: Results
    Service-->>Controller: SearchAlbaResponseDto[]
    Controller-->>User: 200 OK + filtered results
Loading
sequenceDiagram
    actor User
    participant Controller as Store Review<br/>Controller
    participant Service as Store Review<br/>Service
    participant Repo as Store Review<br/>Repository
    participant DB as Database

    User->>Controller: GET /reviews/{storeId} (JWT token)
    Controller->>Controller: `@Security`('jwt') validates<br/>@Get('/{storeId}') extracts path param
    Controller->>Service: getStoreReviewById(storeId)
    Service->>Service: Convert storeId string<br/>to Buffer
    Service->>Repo: findReviewsByStoreId(storeId)
    Repo->>DB: Query reviews by store ID<br/>(with user + store relations)
    DB-->>Repo: Review records
    Repo-->>Service: Raw review data
    Service->>Service: Map to StoreReviewDto<br/>(reviews array)
    Service-->>Controller: StoreReviewDto
    Controller->>Controller: Set HTTP 201
    Controller-->>User: 201 Created + reviews
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • PR #38: Implements JWT refactoring pattern with user UUID extraction from request and propagation through service/repository layers.
  • PR #48: Extends alba search feature by adding JWT authentication and user-specific filtering logic to existing search endpoints.
  • PR #32: Modifies store review controller; this PR adds a new endpoint method to the same controller class.

Suggested labels

✨ feat

Suggested reviewers

  • codie0226
  • s0-yeon
  • gkdmsgus
🚥 Pre-merge checks | ✅ 6
✅ Passed checks (6 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the two main features: store review retrieval and filtering for alba search by user.
Description check ✅ Passed The description covers all main sections with linked issue, detailed work content with explanations and screenshots, and test results.
Linked Issues check ✅ Passed All code changes implement the requirements from issue #67: store review retrieval endpoint and search filtering to exclude applied postings.
Out of Scope Changes check ✅ Passed All code changes are directly related to the two main objectives from issue #67; no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Merge Conflict Detection ✅ Passed ✅ No merge conflicts detected when merging into main

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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 and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@src/controller/search_alba_controller.ts`:
- Line 22: Remove the mandatory `@Security`('jwt') decorator so requests aren't
rejected; instead, make authentication optional by removing or commenting out
`@Security`('jwt') and within the search handler (the method that computes
userBuffer) attempt to extract and verify the JWT manually (e.g., read
Authorization header, call the existing token verification helper or jwt
service), set userBuffer to the decoded user when verification succeeds and to
undefined when there is no token or verification fails, and ensure the rest of
the logic in that method uses userBuffer possibly being undefined to return
unfiltered results for unauthenticated users.
- Around line 30-32: The code unsafely assumes req.user exists when creating
userBuffer from uuidToBuffer; update the handler in search_alba_controller to
defensively check req.user (e.g., if (!req.user || typeof (req.user as any).id
!== 'string') ) before reading the id, and handle the missing user according to
auth semantics (return a 401/unauthorized error or proceed as anonymous) rather
than directly casting; then derive userId from the validated object and call
uuidToBuffer(userId) to set userBuffer.

In `@src/controller/store_review_controller.ts`:
- Around line 41-53: The GET handler getStoreReview declares a 200
SuccessResponse but calls this.setStatus(201); update getStoreReview to use the
correct status for a retrieval (call this.setStatus(200) or remove the setStatus
call so default 200 is used) and ensure the call sites around getStoreReviewById
remain unchanged; adjust only the this.setStatus invocation in the
getStoreReview method.

In `@src/service/search_alba_service.ts`:
- Line 10: The getFilteredAlba function signature requires a Buffer but should
accept unauthenticated calls: change the parameter in getFilteredAlba(params:
SearchAlbaRequestDto, userBuffer?: Buffer): Promise<SearchAlbaResponseDto[]> and
update all call sites to pass undefined when no user is present; also remove or
make the controller's `@Security`('jwt') decorator optional so unauthenticated
requests reach the controller, and ensure any logic inside getFilteredAlba that
assumes userBuffer is present guards for undefined (e.g., only apply filtering
when userBuffer is truthy).
🧹 Nitpick comments (3)
src/repository/store_review_repository.ts (1)

49-58: Consider using select instead of include: true to avoid fetching sensitive columns.

include: { user: true, store: true } loads every column from the user and store tables. If those tables contain sensitive fields (password hashes, emails, etc.), they'll be held in memory even though the service only uses user_name and store_name. The same pattern exists in createStoreReview above.

♻️ Suggested change
 export const findReviewsByStoreId = async (storeId: Buffer) => {
     return await prisma.store_review.findMany({
         where: { store_id: new Uint8Array(storeId) },
         include: {
-            user:true,
-            store:true
+            user: { select: { user_name: true } },
+            store: { select: { store_name: true } }
         },
         orderBy: { created_at: 'desc' }
     });
 };
src/service/store_review_service.ts (2)

25-49: No validation on storeIdStr — invalid UUID will throw an unhandled error.

If storeIdStr is not a valid UUID, uuidToBuffer will throw, resulting in a 500 to the client with no meaningful message. Consider validating the input or wrapping with a try/catch that returns a 400-level error.

Also, the function name getStoreReviewById suggests fetching a single review; getReviewsByStoreId would better describe its behavior.


22-25: Inconsistent indentation — this top-level function is indented as if it were a class member.

Lines 22–49 have extra indentation compared to addReview above. Minor formatting nit.

* @returns 조건에 맞는 알바 리스트
*/
@Get('search')
@Security('jwt')
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

@Security('jwt') blocks unauthenticated users entirely.

Per the PR objective, unauthenticated users should still see unfiltered results. With @Security('jwt'), they'll receive a 401 instead. Consider making authentication optional (e.g., extract the user from the token manually without enforcing @Security) so unauthenticated requests pass through with userBuffer as undefined.

🤖 Prompt for AI Agents
In `@src/controller/search_alba_controller.ts` at line 22, Remove the mandatory
`@Security`('jwt') decorator so requests aren't rejected; instead, make
authentication optional by removing or commenting out `@Security`('jwt') and
within the search handler (the method that computes userBuffer) attempt to
extract and verify the JWT manually (e.g., read Authorization header, call the
existing token verification helper or jwt service), set userBuffer to the
decoded user when verification succeeds and to undefined when there is no token
or verification fails, and ensure the rest of the logic in that method uses
userBuffer possibly being undefined to return unfiltered results for
unauthenticated users.

Comment on lines +30 to +32
//UUID 문자열 Buffer로 변환
const userId = (req.user as unknown as { id: string }).id;
const userBuffer=Buffer.from(uuidToBuffer(userId))
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Unsafe access to req.user — will crash if user context is absent.

The double cast (req.user as unknown as { id: string }).id will throw a TypeError at runtime if req.user is undefined. While @Security('jwt') should guarantee a user, if authentication is made optional (per the other comment), this will break. Even with mandatory auth, a defensive check is safer.

Proposed fix (supports optional auth)
-        const userId = (req.user as unknown as { id: string }).id;
-        const userBuffer=Buffer.from(uuidToBuffer(userId))
-
-        const result = await getFilteredAlba(params,userBuffer)
+        let userBuffer: Buffer | undefined;
+        if (req.user) {
+            const userId = (req.user as unknown as { id: string }).id;
+            userBuffer = Buffer.from(uuidToBuffer(userId));
+        }
+
+        const result = await getFilteredAlba(params, userBuffer)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
//UUID 문자열 Buffer로 변환
const userId = (req.user as unknown as { id: string }).id;
const userBuffer=Buffer.from(uuidToBuffer(userId))
//UUID 문자열 Buffer로 변환
let userBuffer: Buffer | undefined;
if (req.user) {
const userId = (req.user as unknown as { id: string }).id;
userBuffer = Buffer.from(uuidToBuffer(userId));
}
const result = await getFilteredAlba(params, userBuffer)
🤖 Prompt for AI Agents
In `@src/controller/search_alba_controller.ts` around lines 30 - 32, The code
unsafely assumes req.user exists when creating userBuffer from uuidToBuffer;
update the handler in search_alba_controller to defensively check req.user
(e.g., if (!req.user || typeof (req.user as any).id !== 'string') ) before
reading the id, and handle the missing user according to auth semantics (return
a 401/unauthorized error or proceed as anonymous) rather than directly casting;
then derive userId from the validated object and call uuidToBuffer(userId) to
set userBuffer.

Comment on lines +41 to +53
@Get('/{storeId}')
@Security('jwt')
@SuccessResponse('200','조회 성공')
@Response('400','Bad Request')
@Response('500','Internal Server Error')
public async getStoreReview(
@Path() storeId: string,
): Promise<StoreReviewDto>{

const result= await getStoreReviewById(storeId)
this.setStatus(201);
return result;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Status code mismatch: setStatus(201) on a GET endpoint that declares @SuccessResponse('200').

Line 43 declares @SuccessResponse('200', ...) but Line 51 sets status to 201. For a retrieval endpoint, the correct status is 200. This mismatch is also visible in the PR screenshot (Image 1) showing "201 Undocumented".

🐛 Fix
-        this.setStatus(201);
+        this.setStatus(200);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@Get('/{storeId}')
@Security('jwt')
@SuccessResponse('200','조회 성공')
@Response('400','Bad Request')
@Response('500','Internal Server Error')
public async getStoreReview(
@Path() storeId: string,
): Promise<StoreReviewDto>{
const result= await getStoreReviewById(storeId)
this.setStatus(201);
return result;
}
`@Get`('/{storeId}')
`@Security`('jwt')
`@SuccessResponse`('200','조회 성공')
`@Response`('400','Bad Request')
`@Response`('500','Internal Server Error')
public async getStoreReview(
`@Path`() storeId: string,
): Promise<StoreReviewDto>{
const result= await getStoreReviewById(storeId)
this.setStatus(200);
return result;
}
🤖 Prompt for AI Agents
In `@src/controller/store_review_controller.ts` around lines 41 - 53, The GET
handler getStoreReview declares a 200 SuccessResponse but calls
this.setStatus(201); update getStoreReview to use the correct status for a
retrieval (call this.setStatus(200) or remove the setStatus call so default 200
is used) and ensure the call sites around getStoreReviewById remain unchanged;
adjust only the this.setStatus invocation in the getStoreReview method.

* @returns 조건에 맞는 알바 리스트
*/
export const getFilteredAlba = async (params:SearchAlbaRequestDto):Promise<SearchAlbaResponseDto[]>=>{
export const getFilteredAlba = async (params:SearchAlbaRequestDto,userBuffer:Buffer):Promise<SearchAlbaResponseDto[]>=>{
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

userBuffer should be optional to support unauthenticated users.

The PR objective states that unauthenticated users should see unfiltered results, but userBuffer is typed as a required Buffer. Combined with the @Security('jwt') decorator on the controller, unauthenticated requests will be rejected with 401 instead of returning unfiltered results.

If the intent is to support both authenticated and unauthenticated access, make userBuffer optional here and in the controller (remove @Security('jwt') or make it optional), passing undefined when no user is present.

Proposed fix
-export const getFilteredAlba = async (params:SearchAlbaRequestDto,userBuffer:Buffer):Promise<SearchAlbaResponseDto[]>=>{
+export const getFilteredAlba = async (params:SearchAlbaRequestDto,userBuffer?:Buffer):Promise<SearchAlbaResponseDto[]>=>{
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export const getFilteredAlba = async (params:SearchAlbaRequestDto,userBuffer:Buffer):Promise<SearchAlbaResponseDto[]>=>{
export const getFilteredAlba = async (params:SearchAlbaRequestDto,userBuffer?:Buffer):Promise<SearchAlbaResponseDto[]>=>{
🤖 Prompt for AI Agents
In `@src/service/search_alba_service.ts` at line 10, The getFilteredAlba function
signature requires a Buffer but should accept unauthenticated calls: change the
parameter in getFilteredAlba(params: SearchAlbaRequestDto, userBuffer?: Buffer):
Promise<SearchAlbaResponseDto[]> and update all call sites to pass undefined
when no user is present; also remove or make the controller's `@Security`('jwt')
decorator optional so unauthenticated requests reach the controller, and ensure
any logic inside getFilteredAlba that assumes userBuffer is present guards for
undefined (e.g., only apply filtering when userBuffer is truthy).

@codie0226 codie0226 merged commit 44d6214 into UMC-AlbaLog:main Feb 17, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] 스토어 리뷰 조회기능 및 대타알바 검색 필터링 조건 추가

3 participants