feat(req-013): add portfolio-list-user-required requirement and batch

- Add REQ-013: Portfolio list filtered by user requirement with acceptance criteria
- Add DCY-003 discovery document for portfolio list user filtering
- Create BAT-003 batch with planning, design, implementation, and verification
- Enhance app/cli/commands/portfolio.py with user-based list filtering
- Add comprehensive tests for portfolio list CLI command with user filtering
- Update docs indices (discovery, srs, batches)
- Improve README with latest capability status
This commit is contained in:
2026-05-02 13:22:41 +00:00
parent b4d964253b
commit 2f686f79ce
12 changed files with 699 additions and 13 deletions
@@ -0,0 +1,143 @@
# 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 <username>` 옵션을 필수로 지정하여 CLI 실행 시 항상 특정 사용자의 포트폴리오만 조회하도록 강제한다.
- username을 `owner_user_id`(UUID)로 변환하는 로직을 CLI 내부에 추가하여, `PortfolioService.list_portfolios` 호출 시 소유자 필터가 항상 적용되게 한다.
## Requirement
- CLI `pfhub portfolio list` 명령은 `--user <username>` 옵션을 필수로 받아야 한다.
- `--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 <username>` 옵션 추가 및 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 계획 수립
+5 -1
View File
@@ -74,7 +74,7 @@
## Next Requirement ID
- Current: `REQ-013`
- Current: `REQ-014`
- Rule: `Requirement Register`에 있는 가장 큰 REQ 번호보다 정확히 1 커야 한다.
## Requirement Register
@@ -93,9 +93,13 @@
| REQ-010 | credential_payload Fernet 암호화 및 startup validation | Non-Functional | Approved | High | repository-maintainers | [REQ-010](./Non-Functional/req-010_credential-payload-fernet-encryption.md) |
| REQ-011 | trex-basic 계약 반영을 위한 baseline 문서 갱신 | Documentation | Approved | Medium | repository-maintainers | [REQ-011](./Documentation/req-011_baseline-docs-update-for-trex-basic-contract.md) |
| REQ-012 | service-token rotate CLI 명령 구현 | Interface | Approved | Medium | repository-maintainers | [REQ-012](./Interface/req-012_service-token-rotate-cli.md) |
| REQ-013 | CLI `portfolio list --user` 필수화 및 소유자 기반 조회 | Interface | Implemented | Medium | repository-maintainers | [REQ-013](./Interface/req-013_portfolio-list-user-required.md) |
## Recent Change Log Summary
- 2026-05-02: REQ-013 Implemented 전환 — BAT-003 verification evidence 확인 (41 passed)
- 2026-05-02: REQ-013 Approved 전환 — CLI `portfolio list --user` 필수화 및 소유자 기반 조회 (source Discovery: dcy-003)
- 2026-05-02: REQ-013 Proposed 생성 — CLI `portfolio list --user` 필수화 및 소유자 기반 조회 (source Discovery: dcy-003)
- 2026-05-02: REQ-012 Approved 직행 (minor-change) — service-token rotate CLI 명령 구현
- 2026-05-02: REQ-011 Approved 전환 — trex-basic 계약 반영을 위한 baseline 문서 갱신 (source Discovery: dcy-002)
- 2026-05-02: REQ-010 Approved 전환 — credential_payload Fernet 암호화 및 startup validation (source Discovery: dcy-002)