Skip to content

FEAT: 리포트 목록 조회 기능 추가 - #19

Merged
whgkdwnd merged 5 commits into
mainfrom
이동호2
Jul 9, 2026

Hidden character warning

The head ref may contain hidden characters: "\uc774\ub3d9\ud6382"
Merged

whgkdwnd merged 5 commits into
mainfrom
이동호2

Conversation

@LeeDongHo11

@LeeDongHo11 LeeDongHo11 commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • 로그인 사용자가 본인 리포트를 /api/reports에서 페이지/페이지당 개수로 조회할 수 있는 목록 API를 추가했습니다(전체 수·현재 페이지·페이지당 개수·항목 목록 포함).
  • Bug Fixes
    • JWT 기반 인증으로 안정화했으며, 토큰 미제공/만료/유효성 오류/사용자 매칭 실패 시 일관된 401을 반환하도록 개선했습니다.
    • 삭제되지 않은 리포트만 반영하고 정렬 타이브레이커 및 총계 보정도 함께 반영했습니다.
  • Documentation
    • Claude Code 참조용 AGENTS.md를 추가/갱신했습니다.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0dd93d62-8d09-46ec-930d-1d47652c5ec3

📥 Commits

Reviewing files that changed from the base of the PR and between 507e379 and 534c00e.

📒 Files selected for processing (1)
  • backend/app/core/deps.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/app/core/deps.py

Walkthrough

AGENTS.md가 갱신되었고, Clerk JWT 인증이 dev/prod로 분기되며 사용자별 /api/reports 목록 조회 엔드포인트와 응답 스키마, 라우터 연결이 추가되었습니다.

Changes

Reports API 및 인증

Layer / File(s) Summary
프로젝트 문서 갱신
AGENTS.md
모노레포 구조, ETL/아키텍처 운영 규칙, 현재 구현 범위, 커밋 컨벤션을 문서화했습니다.
Clerk JWT 인증 의존성
backend/app/core/deps.py
HTTPBearer 설정, dev 환경의 고정 사용자 처리, JWKS 기반 RS256 검증, sub 클레임 확인, DB 사용자 조회 및 예외 처리를 추가했습니다.
Reports 목록 스키마와 라우트 선언
backend/app/schemas/reports.py, backend/app/routers/reports.py
목록 응답 스키마와 /reports GET 라우트의 응답 모델, 설명, 예시를 정의했습니다.
Reports 목록 조회와 라우터 연결
backend/app/routers/reports.py, backend/app/routers/__init__.py, backend/app/main.py
사용자별 삭제되지 않은 리포트를 페이지네이션으로 조회하고, 라우터 export 및 /api 등록을 추가했습니다.

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

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant get_current_user
  participant PyJWKClient
  participant DB

  Client->>get_current_user: Bearer 토큰 전달
  get_current_user->>PyJWKClient: JWKS 서명 키 조회
  PyJWKClient-->>get_current_user: 키 반환
  get_current_user->>get_current_user: jwt.decode로 RS256 검증
  get_current_user->>DB: clerk_user_id로 User 조회
  DB-->>get_current_user: User 또는 없음
  get_current_user-->>Client: User 반환 또는 401
Loading
sequenceDiagram
  participant Client
  participant reports.router
  participant get_current_user
  participant DB

  Client->>reports.router: GET /api/reports?page&limit
  reports.router->>get_current_user: 현재 사용자 확인
  get_current_user-->>reports.router: User 반환
  reports.router->>DB: total count 조회
  DB-->>reports.router: total
  reports.router->>DB: created_at 내림차순 목록 조회
  DB-->>reports.router: reports
  reports.router-->>Client: total/page/limit/reports 응답
Loading

Possibly related PRs

Suggested reviewers: whgkdwnd

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 리포트 목록 조회 API와 관련 스키마/인증 처리 추가를 잘 요약한 제목입니다.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 이동호2

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🧹 Nitpick comments (1)
backend/app/routers/reports.py (1)

63-86: 🚀 Performance & Scalability | 🔵 Trivial

인덱스 확인 권장.

user_id + is_deleted 조합으로 매 요청마다 count/list 쿼리를 실행합니다. 리포트 테이블이 커질 경우 (user_id, is_deleted, created_at) 복합 인덱스가 있는지 확인하는 것을 권장합니다.

🤖 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 `@backend/app/routers/reports.py` around lines 63 - 86, The reports query in
the `reports` router repeatedly filters by `Report.user_id` and
`Report.is_deleted` and sorts by `Report.created_at`, so verify that the
`Report` model/table has an appropriate composite index for this access pattern.
Add or confirm an index on `Report` covering `user_id`, `is_deleted`, and
`created_at` so the `total` count and paginated `stmt` query stay efficient as
the table grows.
🤖 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 `@AGENTS.md`:
- Line 100: Update the `get_current_user` documentation in AGENTS.md to match
the actual implementation: it should describe Clerk JWT verification and
returning the current user, and note that `/api/reports` uses it. Remove the
outdated note about raising 501 and not being used anywhere, and keep the
surrounding guidance consistent with the current auth flow and related symbols
like `get_current_user` and `/api/reports`.

In `@backend/app/core/deps.py`:
- Around line 22-67: `get_current_user` is missing the required `ENV=dev`
bypass. Update this dependency to check `settings.ENV` (or the existing
environment flag used elsewhere) before JWT validation, and when it is `dev`,
skip the Clerk token decode path and return the fixed development user from the
DB. Keep the bypass scoped only to `get_current_user`, preserve the existing 401
behavior for non-dev environments, and do not change any `X-Admin-Key` handling.
- Around line 44-48: The exception handling in the token verification path is
too broad and drops the original traceback. Update the logic in the
authentication dependency around the JWT/JWKS validation flow to catch only the
expected verification/authentication errors instead of a blanket Exception, and
preserve the original exception by re-raising the HTTPException with explicit
exception chaining. Keep server/config/JWKS failures distinguishable from
invalid-token cases by handling them separately in the relevant dependency
function.
- Around line 34-42: `verify_clerk_token`에서 매 요청마다 새로 만드는 `jwt.PyJWKClient` 사용을
제거하고, 모듈 레벨 싱글턴이나 재사용 가능한 공용 의존성으로 JWKS 클라이언트를 공유하도록 바꾸세요.
`settings.CLERK_JWKS_URL`로 생성한 `PyJWKClient`를 한 번만 만들고,
`get_signing_key_from_jwt` 호출은 그 인스턴스를 통해 수행해 캐시가 유지되게 하세요.

In `@backend/app/routers/reports.py`:
- Around line 83-86: The reports query currently orders only by
Report.created_at, which can make pagination unstable when multiple rows share
the same timestamp. Update the ordering in the reports listing query to add a
unique tie-breaker such as Report.id after created_at, so the result order is
deterministic across pages. Use the query chain in the reports router where
Report.created_at.desc() is applied and extend it with an additional descending
sort on the unique identifier.

---

Nitpick comments:
In `@backend/app/routers/reports.py`:
- Around line 63-86: The reports query in the `reports` router repeatedly
filters by `Report.user_id` and `Report.is_deleted` and sorts by
`Report.created_at`, so verify that the `Report` model/table has an appropriate
composite index for this access pattern. Add or confirm an index on `Report`
covering `user_id`, `is_deleted`, and `created_at` so the `total` count and
paginated `stmt` query stay efficient as the table grows.
🪄 Autofix (Beta)

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: 42b3ca1e-a4bd-4f0c-b821-bbd267e42231

📥 Commits

Reviewing files that changed from the base of the PR and between 7275b55 and 2394052.

📒 Files selected for processing (6)
  • AGENTS.md
  • backend/app/core/deps.py
  • backend/app/main.py
  • backend/app/routers/__init__.py
  • backend/app/routers/reports.py
  • backend/app/schemas/reports.py

Comment thread AGENTS.md Outdated
Comment thread backend/app/core/deps.py Outdated
Comment thread backend/app/core/deps.py
Comment thread backend/app/core/deps.py Outdated
Comment on lines +44 to +48
except Exception:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="유효하지 않은 인증 토큰입니다",
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

포괄적 except Exception 및 raise ... from 누락.

모든 예외(네트워크 오류, 잘못된 CLERK_JWKS_URL 설정, JWKS 파싱 실패 등)를 동일하게 "유효하지 않은 인증 토큰입니다" 401로 뭉뚱그리고, 원본 트레이스백도 버려집니다(Ruff BLE001/B904). 서버 설정 오류까지 401로 감춰 디버깅이 어려워질 수 있습니다.

As per static analysis hints (Ruff BLE001, B904).

🛠️ Proposed fix
-    except Exception:
+    except jwt.PyJWTError as exc:
         raise HTTPException(
             status_code=status.HTTP_401_UNAUTHORIZED,
             detail="유효하지 않은 인증 토큰입니다",
-        )
+        ) from exc
📝 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
except Exception:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="유효하지 않은 인증 토큰입니다",
)
except jwt.PyJWTError as exc:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="유효하지 않은 인증 토큰입니다",
) from exc
🧰 Tools
🪛 Ruff (0.15.20)

[warning] 44-44: Do not catch blind exception: Exception

(BLE001)


[warning] 45-48: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)

🤖 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 `@backend/app/core/deps.py` around lines 44 - 48, The exception handling in the
token verification path is too broad and drops the original traceback. Update
the logic in the authentication dependency around the JWT/JWKS validation flow
to catch only the expected verification/authentication errors instead of a
blanket Exception, and preserve the original exception by re-raising the
HTTPException with explicit exception chaining. Keep server/config/JWKS failures
distinguishable from invalid-token cases by handling them separately in the
relevant dependency function.

Source: Linters/SAST tools

Comment thread backend/app/routers/reports.py Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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 `@backend/app/core/deps.py`:
- Line 131: The User query filter in the dependency logic uses a boolean
comparison that triggers Ruff E712 and is inconsistent with the rest of the PR.
Update the filter in the relevant dependency function that builds the User
lookup to use User.is_deleted.is_(False) instead of comparing to False directly,
matching the style already used in reports.py and keeping the SQLAlchemy boolean
check consistent.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a2bd7292-e358-4c54-86ea-a1b21812c3c3

📥 Commits

Reviewing files that changed from the base of the PR and between 2394052 and 2e56c50.

📒 Files selected for processing (4)
  • backend/app/core/deps.py
  • backend/app/main.py
  • backend/app/routers/__init__.py
  • backend/app/routers/reports.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/app/main.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Inline review comments failed to post. This is likely due to GitHub's internal server error or limits when posting large numbers of comments. If you are seeing this consistently it is likely a permissions issue. Please check "Moderation" -> "Code review limits" under your organization settings.

Actionable comments posted: 1

🤖 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 `@backend/app/core/deps.py`:
- Line 131: The User query filter in the dependency logic uses a boolean
comparison that triggers Ruff E712 and is inconsistent with the rest of the PR.
Update the filter in the relevant dependency function that builds the User
lookup to use User.is_deleted.is_(False) instead of comparing to False directly,
matching the style already used in reports.py and keeping the SQLAlchemy boolean
check consistent.
🪄 Autofix (Beta)

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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: a2bd7292-e358-4c54-86ea-a1b21812c3c3

📥 Commits

Reviewing files that changed from the base of the PR and between 2394052 and 2e56c50.

📒 Files selected for processing (4)
  • backend/app/core/deps.py
  • backend/app/main.py
  • backend/app/routers/__init__.py
  • backend/app/routers/reports.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • backend/app/main.py
🛑 Comments failed to post (1)
backend/app/core/deps.py (1)

131-131: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

== False 대신 .is_(False) 사용.

Ruff E712 오류이며, 같은 PR의 reports.py는 Report.is_deleted.is_(False)를 쓰고 있어 스타일도 불일치합니다.

🛠️ 제안 수정
-        .filter(User.clerk_user_id == clerk_user_id, User.is_deleted == False)
+        .filter(User.clerk_user_id == clerk_user_id, User.is_deleted.is_(False))
📝 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.

        .filter(User.clerk_user_id == clerk_user_id, User.is_deleted.is_(False))
🧰 Tools
🪛 Ruff (0.15.20)

[error] 131-131: Avoid equality comparisons to False; use not User.is_deleted: for false checks

Replace with not User.is_deleted

(E712)

🤖 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 `@backend/app/core/deps.py` at line 131, The User query filter in the
dependency logic uses a boolean comparison that triggers Ruff E712 and is
inconsistent with the rest of the PR. Update the filter in the relevant
dependency function that builds the User lookup to use
User.is_deleted.is_(False) instead of comparing to False directly, matching the
style already used in reports.py and keeping the SQLAlchemy boolean check
consistent.

Source: Linters/SAST tools

@whgkdwnd
whgkdwnd merged commit 73c28ae into main Jul 9, 2026
1 check passed
@whgkdwnd
whgkdwnd deleted the 이동호2 branch July 9, 2026 15:13
@coderabbitai coderabbitai Bot mentioned this pull request Jul 9, 2026
whgkdwnd added a commit that referenced this pull request Jul 24, 2026
FEAT: 리포트 목록 조회 기능 추가
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.

2 participants