배경
프로젝트 등록자가 상세 리포트 유료 열람으로 발생한 포인트 정산을 마이페이지에서 확인할 수 있어야 합니다. 프로젝트 자체의 자산·권리 판매 금액과 리포트 콘텐츠 수익은 회계 의미가 다르므로 화면 문구와 정보 구조에서 명확히 분리합니다.
백엔드 API가 아직 배포되지 않은 동안 실제 정산이 동작하는 것처럼 mock/로컬 계산/임의 성공값을 만들지 않습니다. 해당 영역에 정확히 백엔드 미구현과 필요한 API를 표시하고, 실제 API가 준비되면 아래 계약으로 교체합니다.
현재 Frontend 상태
/mypage/my-projects는 현재 소유 프로젝트 목록만 조회하며 상태·저장 수·프로젝트 판매가를 표시합니다.
- 프로젝트별 상세 리포트 정산 합계와 상세 내역 경로가 없습니다.
- 프로젝트 상세의 리포트 구매 패널은 Backend가 반환한 프로젝트별
reportOffer.price/access price를 표시합니다.
- 공통
LoadingSpinner, SectionLoadingSpinner, 구매 확인 대화상자는 이미 있습니다.
화면 범위
/mypage/my-projects
상단에 다음 세 정보를 간결한 요약 영역으로 표시합니다. 실제 원장 수치이므로 의미 없는 장식용 stat·배지·중첩 카드를 추가하지 않습니다.
누적 콘텐츠 정산: summary.netCreatorRevenuePoint
유료 열람 수: summary.purchaseCount - summary.refundCount인 유효 열람 건수
공통 열람가 1,000P
기존 현재 소유 프로젝트 항목에는 다음을 추가합니다.
- 정보 충실도
- 현재 정산율
- 다음 유료 열람 1회 예상 정산액
- 유료 열람 수(프로젝트별
purchaseCount - refundCount)
- 누적 순정산 포인트
/mypage/my-projects/{projectId}/earnings로 이동하는 정산 내역 링크
가격 문구는 반드시 구분합니다.
- 프로젝트 마켓 가격:
프로젝트 판매가
- 상세 리포트 수익:
콘텐츠 정산
판매가 없음처럼 주어가 없는 표현과 둘 다 구매 가격으로 뭉뚱그리는 표현은 사용하지 않습니다.
양도 전에 본인 정산 기록이 있지만 현재 소유자가 아닌 프로젝트는 정산 API 목록에만 존재할 수 있습니다. 현재 프로젝트와 섞어 소유 상태를 오해하게 만들지 말고 이전 프로젝트 정산 영역으로 분리해 프로젝트명, 누적 순정산, 유료 열람 수와 상세 링크만 제공합니다. 새 소유자의 current offer/예상 정산액은 표시하지 않습니다.
/mypage/my-projects/[projectId]/earnings
- 프로젝트명, 현재 소유 여부, 정보 충실도/현재 정산율/1회 예상 정산액(현재 소유자일 때만), 누적 합계를 표시합니다.
- 정산 목록에는 정산/취소 상태, 리포트 버전, 결제 포인트, 등록자 정산 포인트, 플랫폼 몫, 정산 시각과 취소 시각을 표시합니다.
- 상태는 색만으로 구분하지 않고
정산/취소 텍스트를 함께 제공합니다.
- 구매자 개인정보는 UI 타입과 렌더링 코드에도 두지 않습니다.
- 페이지네이션을 제공하고 URL 또는 query state가 뒤로가기에서 보존되게 합니다.
- 무관한 프로젝트 404는 권한 정보가 노출되지 않는 찾을 수 없음 상태로 처리합니다.
정책 표시 규칙
- 점수가 숫자면
정보 충실도 80점 · 정산율 84%처럼 표시합니다.
- 점수가
null이면 정확히 미산정 · 기본 정산율 60%로 표시합니다. 0점으로 변환하지 않습니다.
creatorRevenueBps는 표시 직전에 퍼센트로 formatting하고, 정산율을 클라이언트가 점수로 재계산하지 않습니다.
- 예상 정산액은 API의
expectedCreatorRevenuePoint를 사용합니다. 합계를 현재 점수로 역산하지 않습니다.
- 과거 상세 row는 구매 당시 snapshot이므로 현재 1,000P/현재 정산율로 덮어쓰지 않습니다.
- point와 count는
ko-KR locale 및 tabular number로 표시합니다.
안내 문구는 다음으로 통일합니다.
상세 리포트 열람가는 모든 프로젝트가 1,000P로 동일합니다.
정보 충실도가 높을수록 등록자에게 배분되는 콘텐츠 정산 비율이 높아집니다.
현재 포인트는 데모용이며, 실서비스에서는 추가 결제수단이 제공될 예정입니다.
데이터·상태 경계
- 기존 현재 프로젝트 목록 API와 신규 정산 API는 별도 query로 유지합니다.
- 현재 프로젝트 목록 실패와 정산 API 실패를 page-wide 단일 오류로 합치지 않습니다.
- 프로젝트 목록 실패: 프로젝트 목록 영역만 오류/재시도
- 정산 API 실패: 상단 정산 요약·정산 필드·이전 프로젝트 정산 영역만 오류/재시도
- 오류 메시지는
role="alert"로 전달하고 사용자가 같은 영역에서 재시도할 수 있어야 합니다.
- 최초 section 로딩에는 공통
SectionLoadingSpinner, 버튼 pending에는 비활성 버튼 내부 LoadingSpinner를 사용합니다. 처리 중... 텍스트만 표시하지 않습니다.
- background refetch는 기존 내용을 없애고 전체 spinner로 되돌리지 않습니다.
- 응답은 Zod 등 현재 프로젝트의 runtime validation 경계에서 검증합니다. 현재 offer/access/new purchase의 정책 가격이 1,000이 아니면 조용히 1,000으로 보정하지 말고 계약 오류로 처리합니다.
- API query key는 사용자별 임의
userId가 아니라 /me 정산 자원 의미를 반영하고, 로그아웃/계정 전환 시 이전 사용자 데이터가 노출되지 않게 기존 auth cache 정책과 맞춥니다.
컴포넌트 책임
app/mypage/my-projects/page.tsx와 신규 route page는 metadata/route 조립만 담당하는 얇은 Server Component로 유지합니다.
- 정산 API 호출, runtime schema, mapper/query hook, 목록 요약, 프로젝트 정산 행, 상세 내역을
features/mypage의 응집된 report earnings 경계에 둡니다.
- API 응답 모양, endpoint 문자열과 합계 fallback을 JSX 안에 직접 섞지 않습니다.
- 공통 포인트 formatting이 실제 여러 기능에서 같은 규칙으로 사용될 때만 shared로 올립니다. 정산 전용 UI를
shared/에 넣지 않습니다.
- 목록과 상세에서 합계 정의를 중복 계산하지 말고 API snapshot을 동일한 view model로 mapping합니다.
상세 리포트 구매 UI 변경
- 프로젝트 상세 구매 패널과 구매 확인창은 공통 열람가
1,000P를 표시합니다.
- 프로젝트별 리포트 가격 입력 UI는 만들지 않습니다. 이미 존재하면 제거합니다.
- 구매 확인창의 범위 문구는 상세 리포트 정보 열람권이며 프로젝트 자산·소유권·양도 권리가 포함되지 않는다는 기존 구분을 유지합니다.
- Backend가 반환한 현재 가격이 1,000P가 아니면 결제를 진행하지 않고 계약 오류를 표시합니다.
- 프로젝트 마켓의 프로젝트 판매가와 구매 흐름은 변경하지 않습니다.
접근성·데스크톱 검증
- 데스크톱 해커톤 화면을 우선하되 기본 유동 너비에서 긴 프로젝트명·큰 포인트 합계가 레이아웃을 깨지 않아야 합니다.
- 내역 표를 사용하면 의미 있는 header와 scope를 제공하고, 좁은 너비에서 잘리지 않도록 overflow 또는 행형 레이아웃을 명시합니다.
- 상세 링크와 pagination은 키보드로 조작 가능하고 focus indicator를 유지합니다.
- 로딩/오류/빈 상태가 같은 공간을 급격히 흔들지 않도록 section 단위 높이와 정보 순서를 유지합니다.
정산 내역이 없습니다, 등록한 프로젝트가 없습니다, 이전 프로젝트 정산이 없습니다를 서로 다른 빈 상태로 처리합니다.
검증 항목
해커톤 규칙에 따라 신규 자동 테스트 코드는 추가하지 않습니다. 아래를 TypeScript, ESLint, build와 데스크톱 수동 확인으로 검증합니다.
- 상단 누적 정산·유효 유료 열람 수가 API 전체 summary와 일치
- 프로젝트별 합계와 상세 합계 일치
- 점수
null이 미산정 · 기본 정산율 60%로 표시
- 현재 프로젝트와 이전 소유 프로젝트의 구분 및 상세 접근
- 프로젝트 판매가와 콘텐츠 정산 문구가 섞이지 않음
- 프로젝트 목록만 실패/정산 API만 실패/둘 다 실패 상태가 독립적으로 복구
- 목록·상세 로딩에 공통 spinner 사용, background refetch 중 기존 내용 유지
- POSTED/REVERSED가 텍스트와 시각 상태로 구분
- 구매 확인창에 1,000P 표시, 비정상 가격에서는 구매 차단
- 구매자 개인정보가 응답 schema·view model·화면에 없음
- 요청된 데스크톱 너비와 키보드 탐색에서 overflow/focus 문제 없음
완료 기준
- 등록자가 내 프로젝트에서 전체·프로젝트별 콘텐츠 정산을 원장 기준으로 이해할 수 있습니다.
- 상단 합계, 프로젝트 합계와 상세 내역이 환불 역분개까지 포함해 일치합니다.
- 공통 1,000P 가격, 정보 충실도 기반 정산과 데모 포인트 범위가 오해 없이 표시됩니다.
- 프로젝트 판매가와 상세 리포트 콘텐츠 정산이 문구·컴포넌트·데이터 흐름에서 분리됩니다.
- 실제 API 미구현 상태를 성공처럼 위장하지 않습니다.
관련 이슈
- Backend 공통 열람가·정산 정책: #36
- Backend 등록자 정산 조회 API: #37
- Backend 상세 리포트 구매 기반: #28
배경
프로젝트 등록자가 상세 리포트 유료 열람으로 발생한 포인트 정산을 마이페이지에서 확인할 수 있어야 합니다. 프로젝트 자체의 자산·권리 판매 금액과 리포트 콘텐츠 수익은 회계 의미가 다르므로 화면 문구와 정보 구조에서 명확히 분리합니다.
백엔드 API가 아직 배포되지 않은 동안 실제 정산이 동작하는 것처럼 mock/로컬 계산/임의 성공값을 만들지 않습니다. 해당 영역에 정확히
백엔드 미구현과 필요한 API를 표시하고, 실제 API가 준비되면 아래 계약으로 교체합니다.현재 Frontend 상태
/mypage/my-projects는 현재 소유 프로젝트 목록만 조회하며 상태·저장 수·프로젝트 판매가를 표시합니다.reportOffer.price/accessprice를 표시합니다.LoadingSpinner,SectionLoadingSpinner, 구매 확인 대화상자는 이미 있습니다.화면 범위
/mypage/my-projects상단에 다음 세 정보를 간결한 요약 영역으로 표시합니다. 실제 원장 수치이므로 의미 없는 장식용 stat·배지·중첩 카드를 추가하지 않습니다.
누적 콘텐츠 정산:summary.netCreatorRevenuePoint유료 열람 수:summary.purchaseCount - summary.refundCount인 유효 열람 건수공통 열람가 1,000P기존 현재 소유 프로젝트 항목에는 다음을 추가합니다.
purchaseCount - refundCount)/mypage/my-projects/{projectId}/earnings로 이동하는정산 내역링크가격 문구는 반드시 구분합니다.
프로젝트 판매가콘텐츠 정산판매가 없음처럼 주어가 없는 표현과 둘 다구매 가격으로 뭉뚱그리는 표현은 사용하지 않습니다.양도 전에 본인 정산 기록이 있지만 현재 소유자가 아닌 프로젝트는 정산 API 목록에만 존재할 수 있습니다. 현재 프로젝트와 섞어 소유 상태를 오해하게 만들지 말고
이전 프로젝트 정산영역으로 분리해 프로젝트명, 누적 순정산, 유료 열람 수와 상세 링크만 제공합니다. 새 소유자의 current offer/예상 정산액은 표시하지 않습니다./mypage/my-projects/[projectId]/earnings정산/취소텍스트를 함께 제공합니다.정책 표시 규칙
정보 충실도 80점 · 정산율 84%처럼 표시합니다.null이면 정확히미산정 · 기본 정산율 60%로 표시합니다.0점으로 변환하지 않습니다.creatorRevenueBps는 표시 직전에 퍼센트로 formatting하고, 정산율을 클라이언트가 점수로 재계산하지 않습니다.expectedCreatorRevenuePoint를 사용합니다. 합계를 현재 점수로 역산하지 않습니다.ko-KRlocale 및 tabular number로 표시합니다.안내 문구는 다음으로 통일합니다.
데이터·상태 경계
role="alert"로 전달하고 사용자가 같은 영역에서 재시도할 수 있어야 합니다.SectionLoadingSpinner, 버튼 pending에는 비활성 버튼 내부LoadingSpinner를 사용합니다.처리 중...텍스트만 표시하지 않습니다.userId가 아니라/me정산 자원 의미를 반영하고, 로그아웃/계정 전환 시 이전 사용자 데이터가 노출되지 않게 기존 auth cache 정책과 맞춥니다.컴포넌트 책임
app/mypage/my-projects/page.tsx와 신규 route page는 metadata/route 조립만 담당하는 얇은 Server Component로 유지합니다.features/mypage의 응집된 report earnings 경계에 둡니다.shared/에 넣지 않습니다.상세 리포트 구매 UI 변경
1,000P를 표시합니다.접근성·데스크톱 검증
정산 내역이 없습니다,등록한 프로젝트가 없습니다,이전 프로젝트 정산이 없습니다를 서로 다른 빈 상태로 처리합니다.검증 항목
해커톤 규칙에 따라 신규 자동 테스트 코드는 추가하지 않습니다. 아래를 TypeScript, ESLint, build와 데스크톱 수동 확인으로 검증합니다.
null이미산정 · 기본 정산율 60%로 표시완료 기준
관련 이슈