feat: /api/reports POST/GET/PATCH + 종목별 이력 + 테스트 (#2) #25

Merged
xhh merged 1 commit from issue-2-reports-api into main 2026-04-22 02:45:47 +09:00
Owner

요약

통합 로드맵 Phase 2 의 핵심 — Share Note 대신 DB 에 리포트를 저장/조회.

엔드포인트

  • GET /api/reports (filter: type, ticker, published_only, include_backtest, limit)
  • GET /api/reports/ticker/{ticker}
  • GET /api/reports/{id} (본문 포함 Detail)
  • POST /api/reports (write)
  • PATCH /api/reports/{id} (write)

DELETE 는 두지 않음 (감사 기록 보존).

Pydantic v2.13 해결

type 필드명이 내장 type 과 shadow 되어 에러. Annotated[Literal[...], Field()] 로 감싸 해결.

테스트 (11 case)

TDD 관례대로 test_post_then_get_persists 를 첫 번째로 배치. Summary vs Detail 구분, stock 타입 422 검증, 필터 4종, PATCH persist 포함.

로컬 uv run pytest24 passed (smoke 3 + watchlist 10 + reports 11).

Closes #2

## 요약 통합 로드맵 Phase 2 의 핵심 — Share Note 대신 DB 에 리포트를 저장/조회. ## 엔드포인트 - GET /api/reports (filter: type, ticker, published_only, include_backtest, limit) - GET /api/reports/ticker/{ticker} - GET /api/reports/{id} (본문 포함 Detail) - POST /api/reports (write) - PATCH /api/reports/{id} (write) DELETE 는 두지 않음 (감사 기록 보존). ## Pydantic v2.13 해결 `type` 필드명이 내장 `type` 과 shadow 되어 에러. `Annotated[Literal[...], Field()]` 로 감싸 해결. ## 테스트 (11 case) TDD 관례대로 `test_post_then_get_persists` 를 첫 번째로 배치. Summary vs Detail 구분, stock 타입 422 검증, 필터 4종, PATCH persist 포함. 로컬 `uv run pytest` → **24 passed** (smoke 3 + watchlist 10 + reports 11). Closes #2
/api/reports POST/GET/PATCH + 종목별 이력 + 테스트 (#2)
All checks were successful
Tests (PR) / pytest (pull_request) Successful in 25s
84c83a54b2
통합 로드맵 Phase 2 의 핵심 — Share Note 대신 이 플랫폼 DB 에 리포트를 저장하고 조회. 스킬이 write 스코프로 POST, 뷰어/운영자가 read 스코프로 조회.

## 엔드포인트 (5개)

- GET    /api/reports                     — 목록 (type/ticker/published_only/include_backtest/limit 필터)
- GET    /api/reports/ticker/{ticker}     — 종목별 이력 (stock 리포트)
- GET    /api/reports/{id}                — 단건 상세 (본문 포함)
- POST   /api/reports                     — 저장 (write)
- PATCH  /api/reports/{id}                — 수정 (write) — published 토글, verdict 보정, token_cost 후기록

삭제 엔드포인트는 두지 않음. 리포트는 감사 기록으로 보존.

## 스키마 설계

- ReportCreate: POST 바디. type 필수, stock 타입은 ticker 없으면 422.
- ReportUpdate: 전 필드 선택. 식별 필드(type/date/ticker) 는 수정 불가.
- ReportSummary: 목록/이력용 — content_md/html 제외로 페이로드 경량화
- ReportDetail: 상세용 — 본문 포함 (ReportSummary 상속)

## Pydantic v2.13 workaround

`type` 이라는 필드명이 Python 내장 `type` 과 shadow 되어 "field name clashing with type annotation" 에러 발생. `Annotated[Literal[...], Field()]` 로 감싸 해결. `date` 도 같은 이유로 `from datetime import date as Date`.

## 테스트 (11 case, TDD 관례)

tests/api/test_reports.py:
- test_post_then_get_persists: deps.get_session 회귀 테스트 (첫 번째 배치)
- test_list_omits_content_body / test_detail_includes_content: Summary vs Detail 구분
- test_stock_requires_ticker: 422 검증
- test_ticker_history_filters_by_ticker
- test_type_filter / test_backtest_excluded_by_default / test_published_only_filter
- test_patch_updates_verdict_and_published
- test_missing_id_returns_404

로컬 uv run pytest -> 24 passed (smoke 3 + watchlist 10 + reports 11).

Closes #2

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
xhh merged commit 4614527df0 into main 2026-04-22 02:45:47 +09:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
xhh/financial-data-platform!25
No description provided.