Skip to content

[DEPLOY] ver 1.3.4#21

Merged
goblurry merged 3 commits into
deployfrom
main
Nov 16, 2025
Merged

[DEPLOY] ver 1.3.4#21
goblurry merged 3 commits into
deployfrom
main

Conversation

@goblurry

@goblurry goblurry commented Nov 16, 2025

Copy link
Copy Markdown
Member

🎯 목적

이론학습 카드 API 엔드포인트 추가

📝 주요 변경사항

🔗 관련 이슈/PR

🔄 버전 검토

  • 배포 버전 변경 시 config.py 업데이트 필요

🧪 테스트

  • 로컬 테스트 완료(Swagger UI에서 API 동작 확인)

📋 체크리스트

  • API 스펙 변경사항 문서화 (Swagger 업데이트)
  • 프론트엔드에 필요한 환경 변수 안내
  • 데이터베이스 스키마 변경사항 공유 (schema.sql 업데이트)
  • API 응답 형식 변경 여부 확인
  • CodeRabbit 제안사항 검토 완료

📝 커밋 메시지 규칙
타입 설명
feat 새로운 기능 추가 (API, 서비스 로직 등)
fix 버그 수정 (예외 처리, 로직 오류 등)
refactor 리팩토링 (기능 변화 없이 구조 개선)
style 코드 스타일 수정 (공백, 들여쓰기 등)
docs 문서 수정 (README, Swagger, 주석 등)
test 테스트 코드 추가/수정
chore 설정/빌드 관련 변경 (requirements.txt, .gitignore 등)
perf 성능 개선 (쿼리 최적화 등)
ci CI/CD 관련 설정 변경 (GitHub Actions 등)
config 설정 파일 변경 (config.py 등)

예시: feat: 뉴스 칼럼 추천 API 추가

Summary by CodeRabbit

새로운 기능

  • 학습 카드 관리 기능 추가 - 새로운 API를 통해 학습 카드를 생성, 조회, 수정, 삭제할 수 있으며, 카테고리와 난이도별로 필터링할 수 있습니다.

유지보수

  • 애플리케이션 버전을 1.3.4로 업데이트하였습니다.

@coderabbitai

coderabbitai Bot commented Nov 16, 2025

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

학습 카드 기능을 위한 새로운 모듈을 추가합니다. 데이터 모델, 저장소 클래스, API 라우터를 포함하며 메인 애플리케이션에 통합됩니다. 앱 버전을 1.3.3에서 1.3.4로 업데이트합니다.

Changes

Cohort / File(s) Change Summary
Configuration Update
app/config.py
앱 버전을 1.3.3에서 1.3.4로 변경
Data Models
app/models/learning.py
학습 카드를 위한 6개의 Pydantic 모델 추가: LearningCardBase, LearningCardCreate, LearningCardUpdate, LearningCardResponse, LearningCardsListResponse, LearningCardDetailResponse
Service Layer
app/services/learning/__init__.py, app/services/learning/learning_cards_repository.py
학습 카드 저장소 패키지 추가 및 LearningCardsRepository 클래스 구현 (전체 CRUD 작업, JSON 필드 직렬화/역직렬화, 오류 처리 포함)
Router Module
app/routers/learning.py
학습 카드 엔드포인트용 새로운 FastAPI 라우터 구현: 목록 조회, 단일 조회, 생성, 업데이트, 삭제 작업 포함
Router Registration
app/routers/__init__.py
learning_router import 추가 및 공개 내보내기에 등록
Main Application Integration
app/main.py
learning_router import 추가, 시작 시 init_learning_repository() 호출, 라우터를 FastAPI 앱에 등록

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • app/services/learning/learning_cards_repository.py: JSON 필드 직렬화/역직렬화 로직과 동적 SQL 쿼리 구성 검토 필요
  • app/routers/learning.py: 리포지토리 초기화 패턴과 엔드포인트 오류 처리 로직 검증 필요
  • app/main.py: 시작 시퀀스 통합 및 라우터 등록 순서 확인 필요
  • 새 기능 전반에 걸친 일관된 오류 처리 및 로깅 패턴 검증 필요

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title check ⚠️ Warning 제목은 배포 버전 1.3.4 업데이트를 언급하지만, 실제 주요 변경사항인 '이론학습 카드 API 엔드포인트 추가'를 반영하지 않습니다. 제목이 버전 번호만 포함하고 실질적인 기능 추가를 나타내지 않습니다. 제목을 '[DEPLOY] ver 1.3.4 - 이론학습 카드 API 추가' 또는 'feat: 이론학습 카드 API 엔드포인트 추가 (v1.3.4)' 등으로 수정하여 주요 변경사항을 명확히 반영하세요.
✅ Passed checks (2 passed)
Check name Status Explanation
Description check ✅ Passed PR 설명은 필수 섹션을 모두 포함하며 대부분 완성되었으나, '📝 주요 변경사항' 섹션이 비어있고 제목과 실제 변경 내용 간의 불일치가 있습니다.
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 main

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.

@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)
app/routers/__init__.py (1)

3-5: 학습 카드 라우터가 올바르게 추가되었습니다.

learning_router가 적절하게 임포트 및 내보내기 되었습니다.

참고로 정적 분석 도구가 __all__ 리스트의 알파벳 정렬을 제안하고 있으나, 이는 선택 사항입니다.

Based on static analysis

알파벳 순으로 정렬하려면 다음 diff를 적용할 수 있습니다:

-__all__ = ["report_router", "news_router", "learning_router"]
+__all__ = ["learning_router", "news_router", "report_router"]
app/services/learning/learning_cards_repository.py (1)

16-93: 카드 목록 조회 로직이 올바르게 구현되었습니다.

동적 필터링(category, level, limit)이 적절하게 처리되며, JSON 필드 파싱 로직이 포함되어 있습니다. 에러 발생 시 빈 리스트를 반환하여 안전하게 처리합니다.

JSON 파싱 로직(lines 52-74)이 get_card 메서드(lines 110-132)에서도 중복됩니다. 유지보수성 향상을 위해 공통 헬퍼 메서드로 추출하는 것을 권장합니다.

예시 리팩토링:

def _parse_json_field(self, value):
    """JSON 문자열을 파싱하는 헬퍼 메서드"""
    if isinstance(value, str):
        try:
            return json.loads(value)
        except json.JSONDecodeError:
            pass
    return value

def _parse_row_data(self, row) -> Dict[str, Any]:
    """DB row를 응답 형식으로 변환"""
    return {
        "id": row["id"],
        "title": row["title"],
        "description": row["description"],
        "contents": self._parse_json_field(row["contents"]),
        "category": row["category"],
        "level": row["level"],
        "keywords": self._parse_json_field(row["keywords"]),
        "image_urls": self._parse_json_field(row["image_urls"]),
        "created_at": str(row["created_at"]),
        "updated_at": str(row["updated_at"])
    }

그런 다음 get_all_cardsget_card에서 이 헬퍼를 사용할 수 있습니다.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5042c38 and fd4313c.

📒 Files selected for processing (7)
  • app/config.py (1 hunks)
  • app/main.py (3 hunks)
  • app/models/learning.py (1 hunks)
  • app/routers/__init__.py (1 hunks)
  • app/routers/learning.py (1 hunks)
  • app/services/learning/__init__.py (1 hunks)
  • app/services/learning/learning_cards_repository.py (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
app/main.py (2)
app/routers/news.py (1)
  • init_services (37-50)
app/routers/learning.py (1)
  • init_repository (25-28)
app/routers/learning.py (3)
app/services/database/db_service.py (1)
  • DatabaseService (8-58)
app/services/learning/learning_cards_repository.py (6)
  • LearningCardsRepository (10-274)
  • get_all_cards (16-93)
  • get_card (96-149)
  • create_card (152-203)
  • update_card (206-263)
  • delete_card (266-274)
app/models/learning.py (5)
  • LearningCardCreate (16-18)
  • LearningCardUpdate (21-29)
  • LearningCardResponse (32-48)
  • LearningCardsListResponse (51-55)
  • LearningCardDetailResponse (58-61)
app/services/learning/learning_cards_repository.py (1)
app/services/database/db_service.py (5)
  • DatabaseService (8-58)
  • fetch (46-48)
  • fetchrow (51-53)
  • fetchval (56-58)
  • execute (41-43)
🪛 Ruff (0.14.4)
app/routers/__init__.py

5-5: __all__ is not sorted

Apply an isort-style sorting to __all__

(RUF022)

app/routers/learning.py

51-51: Unused function argument: request

(ARG001)


80-80: Do not catch blind exception: Exception

(BLE001)


81-81: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


82-85: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


84-84: Use explicit conversion flag

Replace with conversion flag

(RUF010)


96-96: Unused function argument: request

(ARG001)


112-115: Abstract raise to an inner function

(TRY301)


124-124: Do not catch blind exception: Exception

(BLE001)


125-125: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


126-129: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


128-128: Use explicit conversion flag

Replace with conversion flag

(RUF010)


141-141: Unused function argument: request

(ARG001)


157-160: Abstract raise to an inner function

(TRY301)


164-167: Abstract raise to an inner function

(TRY301)


176-176: Do not catch blind exception: Exception

(BLE001)


177-177: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


178-181: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


180-180: Use explicit conversion flag

Replace with conversion flag

(RUF010)


193-193: Unused function argument: request

(ARG001)


211-214: Abstract raise to an inner function

(TRY301)


221-224: Abstract raise to an inner function

(TRY301)


228-231: Abstract raise to an inner function

(TRY301)


240-240: Do not catch blind exception: Exception

(BLE001)


241-241: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


242-245: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


244-244: Use explicit conversion flag

Replace with conversion flag

(RUF010)


255-255: Unused function argument: request

(ARG001)


272-275: Abstract raise to an inner function

(TRY301)


279-282: Abstract raise to an inner function

(TRY301)


284-287: Consider moving this statement to an else block

(TRY300)


291-291: Do not catch blind exception: Exception

(BLE001)


292-292: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


293-296: Within an except clause, raise exceptions with raise ... from err or raise ... from None to distinguish them from errors in exception handling

(B904)


295-295: Use explicit conversion flag

Replace with conversion flag

(RUF010)

app/services/learning/learning_cards_repository.py

89-89: Consider moving this statement to an else block

(TRY300)


91-91: Do not catch blind exception: Exception

(BLE001)


92-92: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


147-147: Do not catch blind exception: Exception

(BLE001)


148-148: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


195-195: Consider moving this statement to an else block

(TRY300)


197-197: Do not catch blind exception: Exception

(BLE001)


198-202: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


254-254: Consider moving this statement to an else block

(TRY300)


256-256: Do not catch blind exception: Exception

(BLE001)


257-262: Use logging.exception instead of logging.error

Replace with exception

(TRY400)


271-271: Consider moving this statement to an else block

(TRY300)


272-272: Do not catch blind exception: Exception

(BLE001)


273-273: Use logging.exception instead of logging.error

Replace with exception

(TRY400)

⏰ 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). (1)
  • GitHub Check: test-and-build
🔇 Additional comments (14)
app/services/learning/__init__.py (1)

1-2: 패키지 초기화 파일이 적절합니다.

표준 패키지 구조를 따르고 있으며, 추가 검토 사항이 없습니다.

app/config.py (1)

44-44: 버전 업데이트가 올바르게 반영되었습니다.

배포 버전 1.3.4로의 업데이트가 PR 목표와 일치합니다.

app/models/learning.py (3)

5-13: 모델 정의가 명확하고 적절합니다.

필수 필드와 선택 필드가 잘 구분되어 있으며, level 필드의 범위 검증(1-5)이 올바르게 설정되어 있습니다. contents 필드가 Any 타입으로 정의되어 JSON과 문자열을 모두 처리할 수 있도록 유연하게 설계되었습니다.


21-29: 부분 업데이트를 위한 모델 설계가 적절합니다.

모든 필드가 Optional로 정의되어 있어 부분 업데이트를 지원하며, level 필드의 검증 제약조건(ge=1, le=5)이 유지되고 있습니다.


32-48: 응답 모델 설정이 올바릅니다.

populate_by_namefrom_attributes 설정을 통해 ORM 객체로부터의 변환을 지원하며, 모든 필수 필드가 포함되어 있습니다.

app/main.py (3)

14-16: 학습 카드 기능 통합을 위한 임포트가 적절합니다.

learning_routerinit_learning_repository 임포트가 올바르게 추가되어 기존 패턴과 일관성을 유지하고 있습니다.


159-161: 학습 카드 Repository 초기화가 올바르게 구현되었습니다.

애플리케이션 시작 시 데이터베이스 서비스와 함께 학습 카드 repository를 초기화하며, 적절한 로깅이 포함되어 있습니다.


294-294: 학습 카드 라우터가 올바르게 등록되었습니다.

기존 라우터들과 함께 learning_router가 애플리케이션에 등록되었습니다.

app/routers/learning.py (3)

22-38: Repository 초기화 패턴이 기존 코드와 일관성을 유지합니다.

전역 repository 변수와 초기화 함수 패턴이 app/routers/news.pyinit_services 패턴과 유사하게 구현되어 있습니다. get_repository() 함수는 초기화되지 않은 경우 적절한 503 에러를 반환합니다.


41-85: 목록 조회 엔드포인트가 잘 구현되었습니다.

필터링 옵션(category, level, limit)이 적절하게 지원되며, 에러 처리와 로깅이 포함되어 있습니다. request 매개변수는 현재 사용되지 않지만, 향후 rate limiting 등을 위해 예약된 것으로 보입니다.


88-129: 상세 조회 엔드포인트가 올바르게 구현되었습니다.

존재하지 않는 카드에 대해 404 에러를 적절히 반환하며, 에러 처리가 잘 되어 있습니다.

app/services/learning/learning_cards_repository.py (3)

152-203: 카드 생성 로직이 올바르게 구현되었습니다.

Python 객체를 JSON 문자열로 변환하고, RETURNING 절을 사용하여 생성된 카드 ID를 반환합니다. 에러 처리와 로깅이 적절합니다.


206-263: 카드 수정 로직이 잘 설계되었습니다.

COALESCE를 사용하여 부분 업데이트를 지원하며, JSON 필드 변환 로직이 포함되어 있습니다. updated_at 타임스탬프가 자동으로 갱신됩니다.


266-274: 카드 삭제 로직이 간결하고 명확합니다.

단순하고 효과적인 삭제 구현이며, 적절한 로깅과 에러 처리가 포함되어 있습니다.

Comment thread app/routers/learning.py
@goblurry
goblurry merged commit b12f6e9 into deploy Nov 16, 2025
2 checks 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.

1 participant