# BAT-014 Implementation - Status: completed - Batch: BAT-014 ## Plan Summary - planning.md Delivery Plan에 따라 (1) `PortfolioItem` schema에 `symbol` 추가 → (2) `_portfolio_to_item()` serialization 보강 → (3) CRUD/list 테스트 expectation 갱신 → (4) `docs/interface-contract.md` 계약 반영 → (5) pytest 검증 순서로 구현 완료. - 사용자가 명시한 핵심 요구대로 `GET /v1/portfolios` 는 **asset join 결과를 응답**해야 하므로, repository shape(`_SELECT_PORTFOLIO` + `_row_to_portfolio`)를 유지한 채 응답 schema/문서/테스트를 정합화했다. ## Changed Files - `app/schemas/v1.py` - `PortfolioItem` 에 `symbol: str | None = None` 필드 추가 - `app/api/v1_portfolios.py` - `_portfolio_to_item()` 에 `symbol=portfolio.symbol` 추가 - `tests/test_v1_portfolios_list.py` - GET `/v1/portfolios` 응답의 `symbol == "005930"` 검증 추가 - 기존 `asset_id` 검증 케이스에도 `symbol` assertion 추가 - `tests/test_v1_portfolios_crud.py` - POST/PATCH/DELETE 성공 응답에서 `symbol == "005930"` 검증 추가 - `docs/interface-contract.md` - POST/PATCH/DELETE/GET `/v1/portfolios` 응답 설명에 `symbol` 필드 반영 - GET `/v1/portfolios` 가 server-side `portfolios JOIN assets` 결과를 직렬화한다는 설명 추가 ## Execution Log 1. BAT-014 planning/index와 REQ-025/026/027/028/032를 읽고 구현 범위를 확정했다. 2. `app/schemas/v1.py` 에 `PortfolioItem.symbol` 필드를 추가했다. 3. `app/api/v1_portfolios.py` `_portfolio_to_item()` 에 `symbol=portfolio.symbol` 매핑을 추가했다. 4. `tests/test_v1_portfolios_crud.py` 의 POST/PATCH/DELETE 성공 케이스에 `symbol == "005930"` assertion을 추가했다. 5. `tests/test_v1_portfolios_list.py` 의 service-token list 케이스와 `asset_id` 검증 케이스에 `symbol == "005930"` assertion을 추가했다. 6. `docs/interface-contract.md` 의 POST/PATCH/DELETE/GET `/v1/portfolios` 명세를 갱신해 `symbol` 과 join 기반 응답 계약을 명문화했다. 7. `app/repositories/postgres.py` 를 재검토해 `_row_to_portfolio()` 가 `symbol=row[4]` 를 매핑하고, `get()` / `create_portfolio()` / `update_portfolio()` / `soft_delete_portfolio()` / `list_portfolios()` 가 모두 `_SELECT_PORTFOLIO` 기반 join 결과를 사용함을 확인했다. 8. `./.venv/bin/python -m pytest tests/test_v1_portfolios_crud.py tests/test_v1_portfolios_list.py -q` 실행 → **32 passed in 2.13s**. 9. `./.venv/bin/python -m pytest -q` 전체 회귀 실행 → **371 passed in 11.00s**. ## Validation - Targeted regression: - `./.venv/bin/python -m pytest tests/test_v1_portfolios_crud.py tests/test_v1_portfolios_list.py -q` → **32 passed in 2.13s** - Full regression: - `./.venv/bin/python -m pytest -q` → **371 passed in 11.00s** - Repository join evidence: - `_row_to_portfolio()` 가 `symbol=row[4]` 를 `Portfolio.symbol` 로 매핑 - `get()` / `create_portfolio()` / `update_portfolio()` / `soft_delete_portfolio()` / `list_portfolios()` 가 `_SELECT_PORTFOLIO` join 결과를 재사용 ## Remaining Risks - R1 (Low): 이번 batch의 symbol 회귀는 FastAPI/TestClient + fake repo 중심이다. 다만 repository 코드 inspection으로 실제 Postgres 경로도 `assets.symbol` join 결과를 응답까지 유지함을 확인했다. - R2 (Negligible): pytest 출력에 기존 `HTTP_422_UNPROCESSABLE_ENTITY` deprecation warning 2~3건이 남아 있으나 BAT-014 범위와 직접 관련은 없고 기능 실패는 없다.