# REQ-013: CLI `portfolio list --user` 필수화 및 소유자 기반 조회 - Status: Implemented - Type: Interface - Priority: Medium - Owner: repository-maintainers ## Intent - CLI `pfhub portfolio list`는 현재 `--user` 옵션이 없어 `owner_user_id=None`으로 호출되며 전체 포트폴리오를 반환한다. 이 동작은 소유자 구분 없이 DB 전체를 노출하는 문제가 있다. - `--user ` 옵션을 필수로 지정하여 CLI 실행 시 항상 특정 사용자의 포트폴리오만 조회하도록 강제한다. - username을 `owner_user_id`(UUID)로 변환하는 로직을 CLI 내부에 추가하여, `PortfolioService.list_portfolios` 호출 시 소유자 필터가 항상 적용되게 한다. ## Requirement - CLI `pfhub portfolio list` 명령은 `--user ` 옵션을 필수로 받아야 한다. - `--user` 없이 실행하면 오류 메시지를 출력하고 exit code 1로 종료해야 한다. - `--user`로 전달된 username을 user repository(`get_user_by_username`)로 조회하여 `owner_user_id`(UUID)를 얻고, 이를 `PortfolioService.list_portfolios(owner_user_id=...)` 호출에 전달해야 한다. - 존재하지 않는 username이 전달되면 기존 CLI 오류 출력 형식(Rich Console 또는 typer.echo)과 일관된 오류 메시지를 출력하고 비정상 종료해야 한다. ## Acceptance Criteria 1. Given `--user` 옵션 없이 `pfhub portfolio list`를 실행할 때, When 명령이 실행되면, Then 오류 메시지("--user 옵션이 필요합니다" 또는 동등한 내용)가 출력되고 exit code 1로 종료된다. 2. Given 유효한 username `alice`로 `pfhub portfolio list --user alice`를 실행할 때, When 명령이 실행되면, Then `alice`의 `owner_user_id`로 필터된 포트폴리오 목록만 반환되고 다른 사용자 소유 포트폴리오는 포함되지 않는다. 3. Given 존재하지 않는 username으로 `pfhub portfolio list --user unknown`을 실행할 때, When 명령이 실행되면, Then "사용자를 찾을 수 없습니다" 형태의 오류 메시지가 출력되고 exit code 1로 종료된다. 4. Given in-memory 모드(`pfhub_DB_ENABLED=false`)에서 `pfhub portfolio list --user alice`를 실행할 때, When 명령이 실행되면, Then DB 모드와 동일하게 `alice` 소유 포트폴리오만 반환된다. 5. Given 오류 발생 시, When 오류 메시지가 출력될 때, Then 메시지 형식은 기존 CLI 오류 출력 형식(Rich Console stderr 또는 typer.echo)과 일관성을 유지한다. ## Impacted Area - Docs: - `README.md` — `pfhub portfolio list` 예제 라인에 `--user ` 옵션 추가 및 breaking change 안내 - Modules: - `app/cli/commands/portfolio.py` — `list_portfolios` 명령 시그니처에 `--user` 필수 옵션 추가, username → owner_user_id 변환 로직 추가, `PortfolioService.list_portfolios` 호출 시 `owner_user_id` 전달 - `app/repositories/portfolio_repository.py` — `get_user_by_username` Protocol stub 기존 존재 확인(line 16), 추가 변경 불필요 - `app/repositories/postgres.py` — `get_user_by_username` 기존 구현 확인(line 419), 추가 변경 불필요 - Tests: - `tests/test_cli.py` — AC 1~5 커버 테스트 케이스 추가: - `test_cli_portfolio_list_without_user_exits_error` - `test_cli_portfolio_list_with_valid_user_filters_by_owner` - `test_cli_portfolio_list_with_unknown_user_exits_error` - `test_cli_portfolio_list_in_memory_mode_works` ## Notes - `PortfolioService.list_portfolios` 시그니처는 변경하지 않는다. CLI 호출부에서만 `owner_user_id`를 전달한다 (A-3, dcy-003). - HTTP API `GET /portfolios`의 접근 통제는 이번 REQ 범위 밖이다 (Out of Scope). - `--all` 관리자 전체 조회 옵션은 이번 REQ에 포함하지 않는다. 후속 Discovery로 분리한다. - username → owner_user_id 변환은 `repository.get_user_by_username(username)` 직접 호출로 구현한다. `UserService`에는 해당 메서드가 없음을 확인하였다. - 기존 `_with_service` 헬퍼는 `PortfolioService`만 생성한다. username 조회를 위해 별도로 repository를 직접 사용하거나 `_with_service` callback 안에서 repository 접근이 필요하다. 구현 시 `app_context.repository_factory(settings)` 반환 객체를 통해 `get_user_by_username`을 호출하는 방식으로 처리한다. - Source Discovery: [dcy-003](../../discovery/dcy-003_20260502_portfolio-list-user-required.md) ## Change Log ### CHG-20260502-03 - Date: 2026-05-02 - Author: repository-maintainers #### Change Summary - Status Approved → Implemented. BAT-003(release-candidate) verification evidence 확인 완료. #### Intent - confirm-req-implemented 실행. AC 1~5 전원 evidence 연결 확인, Blocking Issues 없음. #### Evidence Batch - Batch: BAT-003 (release-candidate) - Verification: docs/batches/bat-003_20260502_portfolio-list-user-required/verification.md - Test result: 41 passed (pytest tests/test_cli.py) #### Acceptance Criteria Delta - 없음 #### Impacted Area Delta - Docs: 없음 - Modules: 없음 - Tests: 없음 #### Delivery Trace Delta - Batches: BAT-003 (release-candidate) - Releases: none (draft-release 대기 중) #### Revalidation Impact - Reverification Needed: no - Existing Implementation Invalidated: no - Status Recommendation: keep-current - Follow-up Action: draft-release ### CHG-20260502-02 - Date: 2026-05-02 - Author: repository-maintainers #### Change Summary - Status Proposed → Approved. 승인 게이트 통과. 필수 필드, AC 5개, Impacted Area, Change Log 모두 충족. #### Intent - confirm-req 실행으로 구현 delivery 입력 준비 확정. #### Acceptance Criteria Delta - Added: 없음 - Updated: 없음 - Removed: 없음 #### Impacted Area Delta - Docs: 없음 - Modules: 없음 - Tests: 없음 #### Delivery Trace Delta - Batches: none - Releases: none #### Revalidation Impact - Reverification Needed: no - Existing Implementation Invalidated: no - Status Recommendation: keep-current - Follow-up Action: batch 생성 진행 (draft-batch) ### CHG-20260502-01 - Date: 2026-05-02 - Author: repository-maintainers #### Change Summary - REQ-013 최초 생성 (Proposed). dcy-003 FR-1, FR-2, FR-3 통합. NFR-1, NFR-2는 AC 5에 흡수. #### Intent - dcy-003 확정 Discovery를 REQ backlog로 정규화. #### Acceptance Criteria Delta - Added: - AC 1~5 신규 작성 #### Impacted Area Delta - Docs: - README.md breaking change 안내 추가 항목 - Modules: - app/cli/commands/portfolio.py 신규 변경 - Tests: - tests/test_cli.py 4개 테스트 케이스 신규 추가 #### Delivery Trace Delta - Batches: none (batch 미생성) - Releases: none #### Revalidation Impact - Reverification Needed: no - Existing Implementation Invalidated: no - Status Recommendation: keep-current - Follow-up Action: confirm-req 실행 후 batch 계획 수립