FeaturesHQ (본사)HQ Mode 재생 리포트 (apps/space /admin/playback)

HQ Mode — 재생 리포트 (apps/space /admin/playback)

SPEC #175 (#172 FU-2) 도입. 실 HQ_MANAGER 직접 로그인 표면(apps/space · space.linkmusic.io).

Overview

본사(HQ_MANAGER)가 산하 매장 음악 재생을 일 / 주 / 월 / 커스텀 4 탭으로 조망하는 전용 페이지다. #172 로 playback_daily_rollup(매장×일 KST: played_ms_total·played_ms_trust· track_count·track_count_trust)에 데이터가 쌓이지만 조회 화면이 없던 갭을 메운다. 롤업 위에 조회 endpoint(getHqPlaybackSummary)를 얹고 그 위에 리포트 UI 를 그린다. BE 변경 없이 각 탭이 같은 endpoint 를 적절한 bucket·from·to 로 호출한다.

  • 집계 축(D2): 상단 전사 KPI(총 재생시간·곡수·신탁 비율) + 하단 매장별 테이블(전 탭 공유).
  • 표시(D3): 일별 추이 차트(커스텀 SVG·라이브러리 없음) + 숫자 표. 일 탭만 차트 생략(하루라 막대 1개 무의미).
  • 신탁/비신탁 분리: 재생시간·곡수를 신탁(TRUST)과 일반으로 나눠 표기.
  • 이번 제외: 준수율(영업시간 대비)은 FU-1(영업시간 저장) 선행 필요 → 후속에 열 추가. CSV 내보내기·KOMCA 내보내기(FU-3)도 별개 후속.

시안: 전용 시안 부재. 운영사 apps/admin signup-trend.tsx·stat-dist-card.tsx(막대 추이·차트 라이브러리 없음) 패턴을 미러하되 신탁/일반 스택 막대로 확장. atom-grounded(design-debt 등재).

페이지 구조 (/admin/playback)

page.tsx(server 셸, force-dynamic) + playback-report-client.tsx(client). 본사 모드 셸 layout(/admin/layout.tsx)이 role 가드 + HQShell 을 제공하므로 별도 refresh-aware 가드 없이 client 영역만 렌더한다(감사(#067) 페이지 미러). 조회 파라미터는 client state(단일 페이지라 deep-link 가치 낮음). BFF 토큰은 generated apiFetch/api/backend/... 경유로 서버 전용 보존.

기간 컨트롤 — 4 탭 (hq-playback-tab-{day|week|month|custom})

상단에 공용 Tabs atom 으로 일 / 주 / 월 / 커스텀 탭을 두고, 선택된 탭에 맞는 컨트롤을 아래에 노출한다. 각 탭은 자기 상태를 독립 보유하며 진입 시 아래 기본값을 쓴다. KST 날짜 산술은 UTC 자정 기준으로 결정적 계산(주=월요일 시작·월=1일~말일).

컨트롤조회 파라미터추이 차트기본값
날짜 피커 1개 <input type="date">(hq-playback-day)bucket=DAY, from=to=선택일생략(하루 막대 1개 무의미)오늘(KST)
최근 12주 드롭다운(hq-playback-week-select, 라벨 M/D ~ M/D·월~일)bucket=DAY, from=월요일, to=일요일그 주 일별(7)이번 주
최근 12개월 드롭다운(hq-playback-month-select, 라벨 YYYY년 M월)bucket=DAY, from=1일, to=말일그 달 일별이번 달
커스텀bucket 토글(일별 DAY·주별 WEEK·월별 MONTH·hq-playback-bucket-{DAY|WEEK|MONTH}) + <input type="date"> from/to(hq-playback-from·hq-playback-to)선택 bucket·범위선택 bucket 별bucket=DAY · 최근 30일(to=오늘·from=to−29)
  • 사전 검증(주로 커스텀 탭): from<=to · 범위 상한 366일(BE 검증 최대 1년과 일치)을 클라가 미리 reject(frontend.md §8) — 위반 시 fetch 를 막고(enabled:false) warn 배너(hq-playback-range-error)로 안내(불필요한 400 호출 절약). 일/주/월 탭은 경계가 항상 유효하다.

전사 KPI (total)

3 카드 — 총 재생시간(ms→“N시간 M분”·hq-playback-kpi-duration, 하위 신탁 재생시간)·총 재생 곡수 (hq-playback-kpi-tracks, 하위 신탁 곡수)·신탁 비율(played_ms_trust/played_ms_totalhq-playback-kpi-trust). 로딩 중엔 ”—” 대시.

추이 차트 (series)

주/월/커스텀 탭에서만 렌더하고 일 탭은 생략한다(하루라 막대 1개뿐이라 무의미 — 섹션 자체를 그리지 않음). PlaybackTrendChart(playback-trend-chart.tsx, hq-playback-chart) — 버킷별 재생시간을 커스텀 SVG <rect> 스택 막대로 그린다. 하단=신탁(primary)·상단=일반(primary soft tint) 스택, viewBox height=100 (최댓값 대비 %)·preserveAspectRatio="none" 가로 stretch. 각 버킷 열은 <g>(hq-playback-chart-bar-{i})

  • <title>(hover tooltip: 전체 라벨·총/신탁/일반 재생시간·곡수). x축 라벨은 SVG 밖 HTML(왜곡 회피, 버킷 많으면 최대 ~8개로 thinning). a11y: role="img" + 요약 aria-label + figcaption sr-only 데이터 요약 + 범례 (신탁/일반). 빈 series(또는 전부 0) → 빈 상태(hq-playback-chart-empty). 로딩 → “불러오는 중…”(hq-playback-trend-loading).

매장별 테이블 (stores)

hq-playback-stores-table — 매장(상세 링크 /admin/stores/{storeId} · hq-playback-store-link-{storeId})·재생시간· 신탁 재생시간·곡수·신탁 곡수. 재생시간 desc 는 BE 고정 정렬(FE 재정렬 없음). 빈 상태 (hq-playback-stores-empty)·로딩(hq-playback-stores-loading). 폐점 매장 포함(과거 재생분 보존).

폴링·에러

  • 폴링: 리포트(실시간 아님)라 refetchIntervalInBackground:false 명시(frontend.md §17 — refetchInterval 미설정, 의도만 남김).
  • 에러: fetch 실패 시 공용 ErrorState(hq-playback-error, 재시도=refetch). 401/403/5xx/네트워크(BACKEND_UNREACHABLE) 분리 매핑(본사 감사 idiom 미러).

진입점

  • 대시보드 “재생 상태” 카드(PlaybackStatusCard, HQ Mode 대시보드)에 [기간별 보기] 링크(hq-dash-playback-report-link/admin/playback). “지금”(카드)과 “누적 조망”(리포트)의 두 축.
  • 본사 사이드바(HQSidebar) — 대시보드 바로 아래 재생 리포트 항목(hq-nav-playback, icon BarChart3).

API

GET /api/v1/hq/playback/summary?bucket&from&toHqPlaybackSummaryResponse. hqId 토큰 주체 도출(타 본사 0)·claim↔DB 재검증 403·미인증 401. 상세는 endpoints.

Followups

  • 준비율(영업시간 대비) — FU-1(영업시간 매장 저장) 선행 후 응답·테이블에 열 추가.
  • CSV 내보내기 — 운영사 통계 CSV 패턴 미러(이번 제외).
  • 신탁 KOMCA 내보내기(FU-3) — 외부 규격 게이트(별개).
  • 매장별 페이지네이션 — 수백 매장×1년 대범위 성능 필요 시.