Skip to content

Conversation

@Jihyun3478
Copy link
Contributor

@Jihyun3478 Jihyun3478 commented Dec 16, 2025

🔥 변경 사항

  • SVG Badge API를 JSON 응답 형태로 구현했습니다.
  • LeaderboardRepository를 재사용하여 코드 중복을 제거했습니다.
  • 캐싱은 필요에 따라 이후 도입할 예정입니다!
  • 로컬 테스트 결과는 아래와 같습니다.
스크린샷 2025-12-17 오전 12 46 50

🏷 관련 이슈

  • X

📸 스크린샷 (UI 변경 시 필수)

  • X

📌 체크리스트

  • 기능이 정상적으로 동작하는지 테스트 완료
  • 코드 스타일 가이드 준수 여부 확인
  • 관련 문서 업데이트 완료 (필요 시)

Summary by CodeRabbit

  • 새로운 기능
    • 사용자 통계(조회수·좋아요·포스트 수)와 최근 포스트를 반환하는 SVG 배지 API가 추가되었습니다. 'default'와 'simple' 유형을 쿼리로 선택 가능하며 배지 데이터(사용자 지표 및 최근 포스트 목록)를 반환합니다.
  • 테스트
    • 배지 생성 로직과 리포지토리의 사용자 통계·최근 포스트 조회에 대한 단위 테스트가 확대되어 정상·오류 경로를 폭넓게 검증합니다.
  • 문서
    • 새 SVG 엔드포인트에 대한 API 문서(경로/쿼리 파라미터, 응답 예시 및 오류 코드)가 추가/업데이트되었습니다.

✏️ Tip: You can customize this high-level summary in your review settings.

feat: SVG Badge API 구현

- Controller, Service, Repository 구현
fix: 쿼리 파라미터 오류 수정

- userStatsQuery에 불필요한 ateRange 파라미터 제거
refactor: SVG Badge API 구조 개선 및 응답 Json으로 변경

- assets, withrank 쿼리 파라미터 삭제
- API 응답 Svg에서 Json으로 변경
@Jihyun3478 Jihyun3478 added the enhancement New feature or request label Dec 16, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 16, 2025

Walkthrough

SVG 배지 기능 추가: 요청/응답 DTO, 서비스, 컨트롤러, 라우터가 도입되고 리더보드 저장소에 getUserStats·getRecentPosts 메서드와 관련 단위 테스트, 에러 경로(NotFoundError·DBError)가 추가되었습니다.

Changes

코호트 / 파일(s) 변경 요약
타입/DTO (요청/응답)
src/types/dto/requests/svgRequest.type.ts, <br>src/types/dto/responses/svgResponse.type.ts,<br>src/types/index.ts`
SVG 배지용 요청·쿼리 타입(SvgBadgeType, GetSvgBadgeParams, GetSvgBadgeQuery), 검증 DTO(GetSvgBadgeQueryDto), 응답 타입(BadgeUserData, BadgeRecentPost, BadgeData) 및 BadgeDataResponseDto 추가 및 재수출
서비스 계층
src/services/svg.service.ts,
src/services/__test__/svg.service.test.ts
SvgServicegetBadgeData(username, type, dateRange) 구현(기본형은 최근 게시물 최대 3개 포함, simple형은 제외), 숫자 변환·매핑·에러 전파 로직 및 단위 테스트 추가
컨트롤러
src/controllers/svg.controller.ts
SvgController 클래스와 getSvgBadge 핸들러 추가(경로 파라미터/쿼리 파싱, 서비스 호출, BadgeDataResponseDto 반환, 에러 로깅·next 호출)
라우팅
src/routes/svg.router.ts,
src/routes/index.ts
SVG 전용 라우터 추가 및 / :username/badge GET 엔드포인트 등록(쿼리 DTO 검증 미들웨어, OpenAPI 주석 포함)
리포지토리 및 테스트
src/repositories/leaderboard.repository.ts,
src/repositories/__test__/leaderboard.repo.test.ts
getUserStatsgetRecentPosts 메서드 추가(공통 CTE 재사용, NotFoundError 처리, DBError 처리) 및 해당 SQL 구성·에러 경로를 검증하는 테스트 확장

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant SvgRouter
    participant SvgController
    participant SvgService
    participant LeaderboardRepo
    participant Database

    Client->>SvgRouter: GET /:username/badge?type={type}
    SvgRouter->>SvgRouter: validateRequestDto(query)
    SvgRouter->>SvgController: getSvgBadge(username, type)
    SvgController->>SvgService: getBadgeData(username, type, dateRange)
    SvgService->>LeaderboardRepo: getUserStats(username, dateRange)
    LeaderboardRepo->>Database: Execute stats query (CTE)
    Database-->>LeaderboardRepo: stats row / not found
    alt stats found
        LeaderboardRepo-->>SvgService: user stats
        opt type == "default"
            SvgService->>LeaderboardRepo: getRecentPosts(username, dateRange, limit=3)
            LeaderboardRepo->>Database: Execute recent posts query (CTE)
            Database-->>LeaderboardRepo: recent posts rows
            LeaderboardRepo-->>SvgService: recent posts
        end
        SvgService-->>SvgController: BadgeData
        SvgController-->>Client: 200 { BadgeDataResponseDto }
    else NotFound
        LeaderboardRepo-->>SvgService: NotFoundError
        SvgService-->>SvgController: throw NotFoundError
        SvgController-->>Client: 404
    end
    alt DB error
        LeaderboardRepo-->>SvgService: DBError
        SvgService-->>SvgController: throw DBError
        SvgController-->>Client: 500
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • 집중 검토 필요 항목:
    • leaderboard.repository.ts 내 SQL/CTE 구성, 파라미터 바인딩 및 NotFoundError 분기
    • SvgService.getBadgeData의 type 분기 로직, 숫자 변환 및 recentPosts 매핑
    • 컨트롤러의 응답 DTO 구성(한국어 메시지 포함)과 error→next 흐름
    • 라우터의 validateRequestDto 적용 및 OpenAPI 주석 일관성
    • 추가된 단위/리포지토리 테스트들이 에러 경로와 쿼리 문자열을 정확히 검증하는지

Possibly related PRs

  • PR #44 — leaderboard 쿼리/CTE 및 diff/aggregation 변경과 중복되는 SQL 구성 요소를 포함합니다.
  • PR #27 — buildLeaderboardCteQuery 및 CTE 기반 쿼리 로직 관련 변경과 직접 연관됩니다.
  • PR #31 — 리더보드 쿼리 및 날짜 범위 처리 변경과 코드 레벨 연관성이 있습니다.

Suggested reviewers

  • six-standard
  • ooheunda
  • Nuung

Poem

🐰 깡충, 깡충 새 뱃지 왔네,
통계 모아 반짝이는 한 점,
라우터가 부르면 서비스가 달려가,
리포지토리가 숫자들을 모아오네,
당근 한 입, 커밋엔 축하의 춤! 🥕✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 SVG Badge API 추가라는 실질적인 변경 사항을 명확하게 요약하고 있으며, 제공된 코드 변경 사항과 완벽하게 일치합니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/total-stats-svg

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
Contributor

@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: 2

🧹 Nitpick comments (6)
src/types/dto/requests/svgRequest.type.ts (1)

1-1: 사용하지 않는 import를 제거하세요.

IsString이 import되었지만 파일에서 사용되지 않습니다.

-import { IsEnum, IsOptional, IsString } from 'class-validator';
+import { IsEnum, IsOptional } from 'class-validator';
src/repositories/__test__/leaderboard.repo.test.ts (2)

232-237: 에러 테스트에서 불필요한 이중 호출을 피하세요.

에러 타입과 메시지를 검증하기 위해 getUserStats를 두 번 호출하고 있습니다. 이는 불필요한 중복 실행입니다.

     it('쿼리 에러 발생 시 DBError를 던져야 한다', async () => {
       mockPool.query.mockRejectedValue(new Error('DB connection failed'));
 
-      await expect(repo.getUserStats('test-user', 30)).rejects.toThrow(DBError);
-      await expect(repo.getUserStats('test-user', 30)).rejects.toThrow('사용자 통계 조회 중 문제가 발생했습니다.');
+      await expect(repo.getUserStats('test-user', 30)).rejects.toThrow(
+        expect.objectContaining({
+          name: 'DBError',
+          message: '사용자 통계 조회 중 문제가 발생했습니다.',
+        }),
+      );
     });

294-299: 에러 테스트에서 불필요한 이중 호출을 피하세요.

위의 getUserStats 테스트와 동일하게, getRecentPosts도 두 번 호출되고 있습니다.

     it('쿼리 에러 발생 시 DBError를 던져야 한다', async () => {
       mockPool.query.mockRejectedValue(new Error('DB connection failed'));
 
-      await expect(repo.getRecentPosts('test-user', 30, 3)).rejects.toThrow(DBError);
-      await expect(repo.getRecentPosts('test-user', 30, 3)).rejects.toThrow('최근 게시글 조회 중 문제가 발생했습니다.');
+      await expect(repo.getRecentPosts('test-user', 30, 3)).rejects.toThrow(
+        expect.objectContaining({
+          name: 'DBError',
+          message: '최근 게시글 조회 중 문제가 발생했습니다.',
+        }),
+      );
     });
src/routes/svg.router.ts (1)

62-66: Swagger 문서에서 recentPosts 항목의 스키마가 불완전합니다.

recentPosts 배열 항목의 프로퍼티를 명시하면 API 문서가 더 유용해집니다.

                 recentPosts:
                   type: array
                   items:
                     type: object
+                    properties:
+                      title:
+                        type: string
+                      releasedAt:
+                        type: string
+                      viewCount:
+                        type: number
+                      likeCount:
+                        type: number
+                      viewDiff:
+                        type: number
src/services/__test__/svg.service.test.ts (1)

1-1: 사용하지 않는 Pool 관련 코드를 제거하세요.

Pool이 import되고 mockPool이 생성되지만, LeaderboardRepository 전체가 mock되어 있어 실제로 사용되지 않습니다.

-import { Pool } from 'pg';
 import { DBError, NotFoundError } from '@/exception';
 import { LeaderboardRepository } from '@/repositories/leaderboard.repository';
   beforeEach(() => {
-    const mockPoolObj = {};
-    mockPool = mockPoolObj as jest.Mocked<Pool>;
-
-    const repoInstance = new LeaderboardRepository(mockPool);
+    const repoInstance = new LeaderboardRepository({} as any);
     mockRepo = repoInstance as jest.Mocked<LeaderboardRepository>;
 
     service = new SvgService(mockRepo);
   });

Also applies to: 18-22

src/repositories/leaderboard.repository.ts (1)

85-151: 선택적 개선: 공통 쿼리 로직 추출 고려

getUserStats와 기존 getUserLeaderboard가 유사한 SELECT/집계 로직을 공유합니다. 향후 유지보수를 위해 공통 부분을 private 헬퍼 메서드로 추출하는 것을 고려해볼 수 있습니다. 현재 상태도 동작에 문제는 없습니다.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 442f13e and 764ec4b.

📒 Files selected for processing (10)
  • src/controllers/svg.controller.ts (1 hunks)
  • src/repositories/__test__/leaderboard.repo.test.ts (2 hunks)
  • src/repositories/leaderboard.repository.ts (2 hunks)
  • src/routes/index.ts (2 hunks)
  • src/routes/svg.router.ts (1 hunks)
  • src/services/__test__/svg.service.test.ts (1 hunks)
  • src/services/svg.service.ts (1 hunks)
  • src/types/dto/requests/svgRequest.type.ts (1 hunks)
  • src/types/dto/responses/svgResponse.type.ts (1 hunks)
  • src/types/index.ts (1 hunks)
🧰 Additional context used
🧠 Learnings (4)
📚 Learning: 2024-12-04T13:26:58.075Z
Learnt from: HA0N1
Repo: Check-Data-Out/velog-dashboard-v2-api PR: 5
File: src/middlewares/auth.middleware.ts:116-117
Timestamp: 2024-12-04T13:26:58.075Z
Learning: 'velog-dashboard-v2-api' 코드베이스에서는 `src/types/express.d.ts` 파일에서 Express의 `Request` 인터페이스를 확장하여 `user`와 `tokens` 속성을 추가하였습니다.

Applied to files:

  • src/types/index.ts
📚 Learning: 2024-12-09T11:15:44.429Z
Learnt from: HA0N1
Repo: Check-Data-Out/velog-dashboard-v2-api PR: 6
File: src/types/dto/velog-user.dto.ts:23-30
Timestamp: 2024-12-09T11:15:44.429Z
Learning: `src/types/dto/velog-user.dto.ts` 파일에서 `ProfileDTO` 클래스는 외부에서 import될 필요가 없으므로 export하지 않아도 된다.

Applied to files:

  • src/types/index.ts
📚 Learning: 2024-12-04T13:28:34.692Z
Learnt from: HA0N1
Repo: Check-Data-Out/velog-dashboard-v2-api PR: 5
File: src/types/dto/user-with-token.dto.ts:3-26
Timestamp: 2024-12-04T13:28:34.692Z
Learning: In `src/types/dto/user-with-token.dto.ts`, since the project is using Express instead of NestJS, `nestjs/swagger` cannot be used. Documentation will be implemented later using an Express-specific Swagger library.

Applied to files:

  • src/routes/svg.router.ts
📚 Learning: 2024-12-05T17:21:07.909Z
Learnt from: HA0N1
Repo: Check-Data-Out/velog-dashboard-v2-api PR: 6
File: src/reposities/user.repository.ts:7-15
Timestamp: 2024-12-05T17:21:07.909Z
Learning: Function `findByUserEmail` in `src/reposities/user.repository.ts` is scheduled to be deleted and should be ignored in future code reviews.

Applied to files:

  • src/repositories/leaderboard.repository.ts
🧬 Code graph analysis (6)
src/services/svg.service.ts (2)
src/types/dto/requests/svgRequest.type.ts (1)
  • SvgBadgeType (3-3)
src/types/dto/responses/svgResponse.type.ts (1)
  • BadgeDataResponseDto (19-27)
src/controllers/svg.controller.ts (2)
src/services/svg.service.ts (1)
  • SvgService (5-42)
src/types/dto/requests/svgRequest.type.ts (2)
  • GetSvgBadgeParams (5-7)
  • GetSvgBadgeQuery (9-11)
src/types/dto/requests/svgRequest.type.ts (1)
src/types/index.ts (4)
  • SvgBadgeType (42-42)
  • GetSvgBadgeParams (42-42)
  • GetSvgBadgeQuery (42-42)
  • GetSvgBadgeQueryDto (43-43)
src/repositories/leaderboard.repository.ts (2)
src/utils/date.util.ts (1)
  • getKSTDateStringWithOffset (44-57)
src/exception/index.ts (2)
  • NotFoundError (12-12)
  • DBError (2-2)
src/repositories/__test__/leaderboard.repo.test.ts (2)
src/utils/fixtures.ts (2)
  • mockPool (17-21)
  • createMockQueryResult (70-78)
src/exception/index.ts (2)
  • NotFoundError (12-12)
  • DBError (2-2)
src/services/__test__/svg.service.test.ts (2)
src/services/svg.service.ts (1)
  • SvgService (5-42)
src/repositories/leaderboard.repository.ts (1)
  • LeaderboardRepository (7-191)
🪛 GitHub Actions: Test CI
src/controllers/svg.controller.ts

[error] 9-9: ESLint: Unexpected any. Specify a different type. @typescript-eslint/no-explicit-any

🪛 GitHub Check: build-and-test (20)
src/controllers/svg.controller.ts

[failure] 9-9:
Unexpected any. Specify a different type


[failure] 9-9:
Unexpected any. Specify a different type

src/routes/svg.router.ts

[failure] 74-74:
Unexpected any. Specify a different type

🪛 GitHub Check: build-and-test (21)
src/controllers/svg.controller.ts

[failure] 9-9:
Unexpected any. Specify a different type


[failure] 9-9:
Unexpected any. Specify a different type

src/routes/svg.router.ts

[failure] 74-74:
Unexpected any. Specify a different type

🪛 GitHub Check: build-and-test (22)
src/controllers/svg.controller.ts

[failure] 9-9:
Unexpected any. Specify a different type


[failure] 9-9:
Unexpected any. Specify a different type

src/routes/svg.router.ts

[failure] 74-74:
Unexpected any. Specify a different type

🪛 GitHub Check: build-and-test (23)
src/controllers/svg.controller.ts

[failure] 9-9:
Unexpected any. Specify a different type


[failure] 9-9:
Unexpected any. Specify a different type

src/routes/svg.router.ts

[failure] 74-74:
Unexpected any. Specify a different type

🔇 Additional comments (12)
src/types/dto/requests/svgRequest.type.ts (1)

13-16: LGTM!

DTO 클래스가 올바르게 구현되었습니다. @IsOptional()@IsEnum 데코레이터를 통한 유효성 검사가 적절하며, 생성자에서 기본값 처리도 잘 되어 있습니다.

src/routes/index.ts (1)

7-7: LGTM!

SvgRouter가 기존 라우터 패턴과 일관되게 등록되었습니다.

Also applies to: 21-21

src/repositories/__test__/leaderboard.repo.test.ts (2)

188-230: LGTM!

getUserStats 테스트 케이스들이 잘 구성되어 있습니다. CTE 쿼리 검증, 파라미터 바인딩, NotFoundError 처리 등 주요 시나리오를 포괄적으로 테스트하고 있습니다.


240-293: LGTM!

getRecentPosts 테스트가 적절하게 작성되었습니다. limit 파라미터 바인딩, 정렬 순서, CTE 쿼리 포함 여부 등을 검증하고 있습니다.

src/controllers/svg.controller.ts (1)

14-24: LGTM!

핸들러 로직이 적절합니다. usernametype 추출, 기본값 처리, 서비스 호출, JSON 응답 반환, 그리고 에러 로깅 및 전파가 올바르게 구현되어 있습니다.

src/services/svg.service.ts (1)

5-41: LGTM!

SvgService 구현이 깔끔합니다. 타입에 따른 조건부 데이터 조회, DB 문자열 값의 숫자 변환, 에러 로깅 및 전파가 적절하게 처리되어 있습니다.

src/routes/svg.router.ts (1)

11-13: LGTM!

의존성 주입 체인이 올바르게 구성되어 있습니다. LeaderboardRepository → SvgService → SvgController 순서로 적절하게 연결되어 있습니다.

src/types/dto/responses/svgResponse.type.ts (1)

1-27: LGTM!

DTO 정의가 명확하고 적절하게 타입이 지정되어 있습니다. BadgeUserData, BadgeRecentPost 인터페이스와 BadgeDataResponseDto 클래스가 잘 구성되어 있습니다.

src/services/__test__/svg.service.test.ts (1)

61-137: LGTM!

테스트 케이스들이 포괄적으로 작성되어 있습니다. default/simple 타입 분기, 숫자 변환, 게시글 데이터 변환, dateRange 전파, 에러 전파 등 핵심 시나리오를 잘 커버하고 있습니다.

src/types/index.ts (1)

41-46: LGTM!

SVG 관련 타입 및 DTO export가 기존 파일 구조와 일관되게 추가되었습니다. export typeexport 구분도 올바르게 적용되어 있습니다.

src/repositories/leaderboard.repository.ts (2)

85-120: LGTM! 에러 핸들링이 적절합니다.

NotFoundError를 재throw하고 다른 예외는 DBError로 래핑하는 패턴이 적절합니다. buildLeaderboardCteQuery 재사용으로 코드 중복을 줄인 점도 좋습니다.


122-151: LGTM!

게시글이 없는 경우 빈 배열을 반환하는 것이 적절한 동작입니다. released_at DESC 정렬로 최신 게시글을 먼저 가져오는 로직이 명확합니다.

Copy link
Contributor

@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: 1

🧹 Nitpick comments (2)
src/services/svg.service.ts (1)

8-12: username 파라미터 검증을 추가하는 것을 권장합니다.

빈 문자열이나 공백만 있는 username이 전달될 경우를 방지하기 위해 입력 검증을 추가하는 것이 좋습니다.

메서드 시작 부분에 검증 로직을 추가할 수 있습니다:

 async getBadgeData(
     username: string,
     type: SvgBadgeType,
     dateRange: number = 30,
 ): Promise<BadgeData> {
     try {
+        if (!username || username.trim().length === 0) {
+            throw new Error('Username is required');
+        }
+        
         const userStats = await this.leaderboardRepo.getUserStats(username, dateRange);
src/types/dto/responses/svgResponse.type.ts (1)

13-24: 날짜 형식에 대한 문서화를 추가하는 것을 고려하세요.

releasedAt 필드가 string 타입으로 정의되어 있습니다. ISO 8601 형식 등 예상되는 날짜 형식을 JSDoc 주석으로 명시하면 API 사용자에게 도움이 됩니다.

다음과 같이 JSDoc 주석을 추가할 수 있습니다:

 export interface BadgeRecentPost {
     title: string;
+    /** ISO 8601 date string (e.g., "2025-12-16T15:51:35Z") */
     releasedAt: string;
     viewCount: number;
     likeCount: number;
     viewDiff: number;
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 764ec4b and 678e989.

📒 Files selected for processing (4)
  • src/controllers/svg.controller.ts (1 hunks)
  • src/services/svg.service.ts (1 hunks)
  • src/types/dto/responses/svgResponse.type.ts (1 hunks)
  • src/types/index.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/types/index.ts
  • src/controllers/svg.controller.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/types/dto/responses/svgResponse.type.ts (1)
src/types/dto/responses/baseResponse.type.ts (1)
  • BaseResponseDto (28-40)
🔇 Additional comments (5)
src/services/svg.service.ts (3)

1-6: LGTM! 의존성 주입 패턴이 잘 적용되었습니다.

클래스 구조와 생성자가 깔끔하고, 의존성 주입을 통해 테스트 가능성이 확보되어 있습니다.


37-40: LGTM! 에러 처리가 적절합니다.

에러를 로깅하고 재throw하는 패턴은 적절하며, 호출자가 에러를 처리할 수 있도록 합니다.


14-14: and

src/types/dto/responses/svgResponse.type.ts (2)

1-11: LGTM! 인터페이스 정의가 명확합니다.

BadgeUserData 인터페이스가 잘 정의되어 있고, 필드명이 명확하며 타입이 적절합니다.


26-30: LGTM! DTO 클래스 구현이 적절합니다.

BadgeDataResponseDtoBaseResponseDto를 올바르게 확장하고 있으며, 명시적인 타입을 제공하여 코드 가독성과 타입 안정성을 향상시킵니다.

Copy link
Contributor

@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: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 131fc22 and 9e04ad4.

📒 Files selected for processing (3)
  • src/controllers/svg.controller.ts (1 hunks)
  • src/routes/svg.router.ts (1 hunks)
  • src/services/svg.service.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/routes/svg.router.ts
🧰 Additional context used
🧬 Code graph analysis (1)
src/controllers/svg.controller.ts (4)
src/services/svg.service.ts (1)
  • SvgService (10-41)
src/types/index.ts (2)
  • GetSvgBadgeQuery (42-42)
  • BadgeDataResponseDto (45-45)
src/types/dto/requests/svgRequest.type.ts (1)
  • GetSvgBadgeQuery (9-11)
src/types/dto/responses/svgResponse.type.ts (1)
  • BadgeDataResponseDto (26-30)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: build-and-test (23)
  • GitHub Check: build-and-test (20)
  • GitHub Check: build-and-test (21)
  • GitHub Check: build-and-test (22)
🔇 Additional comments (3)
src/controllers/svg.controller.ts (1)

18-25: 서비스 호출 및 에러 처리 로직이 적절합니다.

서비스 계층 호출, 응답 DTO 구성, 그리고 에러 로깅 및 미들웨어 전달이 올바르게 구현되어 있습니다.

src/services/svg.service.ts (2)

5-8: safeNumber 헬퍼 함수가 잘 구현되었습니다.

명시적인 리턴 타입과 함께 NaN 처리를 안전하게 수행하고 있으며, null/undefined/잘못된 값에 대해 기본값을 반환하는 로직이 정확합니다.


13-40: getBadgeData 메서드 구현이 우수합니다.

  • safeNumber 함수를 모든 숫자 변환에 일관되게 사용하여 NaN 문제를 방지하고 있습니다.
  • 조건부로 recentPosts를 가져오는 로직이 효율적입니다.
  • 에러 로깅 및 재throw 처리가 적절합니다.

@@ -0,0 +1,27 @@
import { NextFunction, RequestHandler, Request, Response } from 'express';
import logger from '@/configs/logger.config';
import { GetSvgBadgeQuery, BadgeDataResponseDto } from '@/types';
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

타입 안전성 개선이 필요합니다.

라인 3에서 GetSvgBadgeParams 타입을 import하지 않고, 라인 10에서 params 타입을 object로 지정한 후 라인 15에서 타입 단언(as { username: string })을 사용하고 있습니다. 이는 TypeScript의 타입 체크를 우회하며, 라우트가 변경될 경우 런타임 에러가 발생할 수 있습니다.

다음 diff를 적용하여 타입 안전성을 개선하세요:

-import { GetSvgBadgeQuery, BadgeDataResponseDto } from '@/types';
+import { GetSvgBadgeQuery, GetSvgBadgeParams, BadgeDataResponseDto } from '@/types';
 import { SvgService } from '@/services/svg.service';
 
 export class SvgController {
   constructor(private svgService: SvgService) {}
 
-  getSvgBadge: RequestHandler = async (
-    req: Request<object, object, object, GetSvgBadgeQuery>,
+  getSvgBadge: RequestHandler<GetSvgBadgeParams, BadgeDataResponseDto, object, GetSvgBadgeQuery> = async (
+    req: Request<GetSvgBadgeParams, BadgeDataResponseDto, object, GetSvgBadgeQuery>,
     res: Response<BadgeDataResponseDto>,
     next: NextFunction,
   ) => {
     try {
-      const { username } = req.params as { username: string };
+      const { username } = req.params;
       const { type = 'default' } = req.query;

Also applies to: 9-15

🤖 Prompt for AI Agents
In src/controllers/svg.controller.ts around lines 3 and 9-15, improve TypeScript
safety by importing GetSvgBadgeParams from '@/types' and using it for the route
params instead of typed as object and then using a runtime type assertion;
change the handler signature to accept params: GetSvgBadgeParams, remove the `as
{ username: string }` assertion, and use the typed params.username directly (and
update any other uses in lines 9-15 to rely on the strongly typed property).

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

None yet

Development

Successfully merging this pull request may close these issues.

2 participants