5.6 KiB
5.6 KiB
Portfolio Ownership and Auth Design
- Related REQ:
REQ-004
목표
- 포트폴리오 리소스에 소유주(
owner_user_id)를 도입해 사용자 단위 데이터 격리를 강제한다. - 기존 RBAC(
read,trade-write,admin)와 소유권 검사 규칙을 결합해 접근 제어를 표준화한다. - frontend와 portfolio-hub가 같은 서버에서 개별 컨테이너로 운영되는 구조에서도 단일 인증 체계로 일관된 권한 모델을 유지한다.
범위
- 포함:
- DB 스키마 변경 및 레거시 데이터 백필
- API/서비스/리포지토리 ownership 정책
- 통합 테스트 및 회귀 테스트 시나리오
- 제외:
- 외부 IdP/OIDC 연동
- 인증 서비스를 별도 프로세스로 분리하는 배포 작업
DB 마이그레이션 설계
Revision Plan
owner_user_idnullable 추가- 레거시 row 백필
- 인덱스 추가
- not null 제약 적용
- 필요 시 FK 제약(
users.id) 적용
권장 DDL 단계
- 컬럼 추가
ALTER TABLE portfolios
ADD COLUMN owner_user_id TEXT;
- 백필 기준 사용자 결정
- 환경변수 기반 bootstrap admin이 있으면 해당 사용자 id를 우선 사용한다.
- 없으면
users.created_at ASC첫 사용자 id를 사용한다. - 사용자 자체가 없으면 migration을 실패시키고 운영자가 사용자 생성 후 재시도한다.
- 레거시 데이터 백필
UPDATE portfolios
SET owner_user_id = :fallback_user_id
WHERE owner_user_id IS NULL;
- 제약 및 인덱스 적용
ALTER TABLE portfolios
ALTER COLUMN owner_user_id SET NOT NULL;
CREATE INDEX idx_portfolios_owner_updated
ON portfolios (owner_user_id, updated_at DESC);
- 선택적 FK 제약
ALTER TABLE portfolios
ADD CONSTRAINT fk_portfolios_owner_user
FOREIGN KEY (owner_user_id) REFERENCES users(id);
롤백 전략
- downgrade에서는 FK, 인덱스, not null 제약 해제 후 컬럼 제거 순서로 진행한다.
- 운영 데이터 보존이 필요하면 컬럼 삭제 대신 nullable 유지 downgrade를 별도 운영 방침으로 둔다.
API 권한 규칙 설계
공통 정책
- 1단계: RBAC 검사 통과 필요
- 2단계: admin이 아니면 ownership 검사 수행
- ownership 검사 기준:
portfolio.owner_user_id == auth_context.user_id auth_context.user_id가 없는 요청은 ownership 필요한 엔드포인트에서403
Endpoint Policy Matrix
| Endpoint | RBAC 최소 권한 | Ownership 적용 | 비고 |
|---|---|---|---|
GET /portfolios |
read | 적용 | admin은 전체, 그 외 owner만 필터 |
GET /portfolios/{portfolio_id} |
read | 적용 | owner 불일치 시 403 |
POST /portfolios |
trade-write | 생성 시 owner 고정 | owner_user_id는 인증 주체로 강제 |
PATCH /portfolios/{portfolio_id} |
trade-write | 적용 | owner 불일치 시 403 |
POST /portfolios/{portfolio_id}/buy |
trade-write | 적용 | owner 불일치 시 403 |
POST /portfolios/{portfolio_id}/sell |
trade-write | 적용 | owner 불일치 시 403 |
POST /portfolios/{portfolio_id}/invest |
trade-write | 적용 | owner 불일치 시 403 |
POST /portfolios/{portfolio_id}/transfer |
trade-write | 적용 | owner 불일치 시 403 |
POST /portfolios/{portfolio_id}/reset |
trade-write | 적용 | owner 불일치 시 403 |
DELETE /portfolios/{portfolio_id} |
admin | admin only | 기존 정책 유지 |
POST/GET/PATCH/DELETE /portfolios/{id}/comments* |
read or trade-write | 적용 | 상위 포트폴리오 ownership을 재사용 |
서비스/리포지토리 반영 포인트
- Domain model:
Portfolio에owner_user_id추가
- Schema:
PortfolioSummary/CreatePortfolioRequest응답/입력 계약에 owner 노출 정책 정의- 외부 입력으로 owner_user_id 수동 지정은 금지
- Repository:
- create 시 owner_user_id 필수 인자
- list/get 시 요청자 컨텍스트 기반 owner 필터 함수 제공
- Service/API:
- request principal을 service 계층으로 전달
- 공통 ownership 가드 함수 도입
frontend 연계 방침
- frontend는 credential 저장/검증 자체를 수행하지 않고 portfolio-hub 인증 API를 사용한다.
- 브라우저 경로는 HttpOnly + Secure cookie 기반 세션을 우선 고려한다.
- 동일 서버 내 별도 컨테이너 운영 시 reverse proxy에서 CORS/Cookie domain 정책을 일관되게 관리한다.
테스트 케이스 목록
Migration
- 기존 portfolios row가 존재할 때 owner_user_id 백필 후 null row가 0건인지 검증
- users가 없는 상태에서 migration 실행 시 실패 동작 검증
- downgrade 시 인덱스/제약 해제가 순서대로 수행되는지 검증
API Authorization
- 사용자 A 소유 portfolio를 사용자 B가 조회하면 403
- 사용자 A 소유 portfolio를 사용자 B가 수정/매매/리셋하면 403
- admin이 타 사용자 portfolio 조회/수정 가능
- 일반 사용자의
GET /portfolios는 본인 소유만 반환 - user_id 없는 bot principal 요청이 ownership 필요 API 호출 시 403
API Creation
POST /portfolios에서 owner_user_id가 인증 사용자로 저장되는지 검증- 요청 body에 owner_user_id를 넣어도 무시되거나 validation 실패하는지 검증
Regression
- 기존 REQ-001 댓글 API가 ownership 정책 적용 후에도 owner 경계 내에서 정상 동작
- 기존 RBAC 오류(
401,403) 계약이 ownership 도입 후에도 유지 - admin delete 동작이 ownership 변경과 충돌 없이 유지
추적 항목
- 본 설계 문서 구현 시
docs/SRS/traceability-matrix.md의REQ-004행에 Issue/PR/Test evidence를 갱신한다.