HQ Mode — 본사 라이브러리 조회 (apps/space /admin/libraries, read-only)
SPEC #080 목록 도입 · #107 상세 도입 (read-only). 실 HQ_MANAGER 직접 로그인 표면(apps/space · space.linkmusic.io) — 운영사 임퍼소네이션(apps/admin)이 아니다.
이 페이지는
apps/space의 실 HQ_MANAGER 본사 모드다. 운영사(OPERATOR)가 라이브러리를 만들고 음원을 할당하는apps/admin/libraries(#053)와는 별개다. 음악 2계층은 “운영사 편집 · 본사 조회”가 모델 불변식 — 본 슬라이스가 그 조회 쪽 라이브러리 층을 채운다(편집·음원 할당은 운영사 전용). 본사 PL 조회(#057)와 같은 패턴.
Overview
HQ_MANAGER 가 apps/space 본사 모드에서 자기 본사 PL 에 담을 후보 라이브러리 목록을 조회
한다(read-only). 가시 범위는 운영사가 만든 모든 라이브러리(plan/type mismatch 게이트는 후속
#060 F1) — 본사가 자기 플랜에 맞는 라이브러리를 골라 PL 에 추가하는 패턴(이미 #057 본사 PL 도
같은 패턴). 생성/편집/삭제·음원 할당은 운영사(apps/admin) 전용 — 본사 모드는 mutating
진입점이 없다.
시안 출처: workspace parent dir — hq-library 전용 시안 부재로 본사 모드 기존 화면 (
design/screens/hq-stores.jsx테이블·검색·페이지네이션, hq-playlist 목록 #057) 스타일과 일관 (임의 디자인 금지). 검색·페이지네이션은 공용ListToolbar/ListPagination(본사/stores#051 관용구)으로 정합.
목록 (/admin/libraries)
apps/space/src/app/admin/libraries/page.tsx(server 셸) + hq-library-list-client.tsx(client).
본사 /admin/playlists(#057)와 동일 이유로 서버사이드 페이지네이션 + client-query
(useListHqLibraries) — q(이름)·type(AI/TRUST 또는 전체)·page·size 를 client state 로 보유한다.
정렬은 서버 고정(name ASC).
- 툴바: 공용
ListToolbar— 검색(라이브러리명, ≤100) + 타입 필터(AI/TRUST/전체) + 적용/초기화. read-only 라 생성 버튼 없음. - 행: 이름(font-medium) · 타입 배지(
StatusPill— AI=info/TRUST=success, 운영사 PL 상세 #057 의LIBRARY_TYPE_META와 일관) · 음원 수(trackCount) · PL 사용 수(playlistCount, 본인 본사 PL 만 카운트) · 수정 시각(updatedAt, KSTformatKstDateTime). - 빈 상태: 검색/필터 0건(
ListNoResultsCTA “라이브러리가 없습니다”) vs 진짜 빈 목록 구분. - 페이지네이션: 공용
ListPagination— 총 N개 + 이전/다음(경계 disabled). - read-only: 생성/편집/삭제·음원 할당 진입점 없음. 라이브러리명 셀은 상세
(
/admin/libraries/[id], #107)로 진입하는 read-only Link 다(본사 매장 목록 #084 패턴 미러 — 행 자체 클릭이 아니라 이름 한 곳,data-testid="hq-library-link-{id}").
상세 (/admin/libraries/[id], SPEC #107)
apps/space/src/app/admin/libraries/[id]/page.tsx(server 셸) + hq-library-detail-client.tsx(client).
본사 PL 상세(#057)·운영사 라이브러리 상세(#053) idiom 을 정확히 미러하되 read-only — 음원 추가/
제거·이름 수정·삭제·체크박스·일괄 제거 진입점이 모두 없다(편집은 운영사 apps/admin 전용).
구조(2 endpoint 분리, BE §D1): 메타는 server fetch(loadHqLibraryRefreshAware →
getHqLibrary), 트랙은 client query(useListHqLibraryMusic, 페이지네이션). 라이브러리당 음원이
카탈로그급으로 커질 수 있어 임베드 대신 서버 페이지네이션(운영사 #053 정확 미러).
- 헤더: 뒤로가기(→
/admin/libraries) + 라이브러리명 + 타입 배지(StatusPill— AI=info/ TRUST=success,HqLibraryDetailResponseType기반) + subtitle음원 N곡 · PL 사용 M개 · 조회 전용. 라이브러리는 단일 타입 묶음이라 타입 배지는 헤더 한 곳에만(트랙별 배지 없음, BE §D3). - 메타 카드(
SummaryCardgrid): 음원 수(trackCount) · PL 사용(playlistCount, hint “이 라이브러리를 사용 중인 본사 PL 수”) · 마지막 수정(formatKstDateTime(updatedAt)). - 트랙 테이블:
useListHqLibraryMusic(libraryId, {page, size:20}). 컬럼 제목 · 길이 (formatTrackDuration— mm:ss, 1시간↑ h:mm:ss, 음수/NaN/undefined → ”—”) · 추가일 (formatKstDateTime(createdAt)). 정렬은 서버 고정(할당 시각 DESC). 로딩 (hq-library-music-list-loading) · 빈(hq-library-music-list-empty“담긴 음원이 없습니다.” CTA 없음) · 에러(hq-library-music-list-error) 분기. 공용ListPagination(1-base 표기, testId 접두hq-library-music-*). - 메타 fetch 실패(detail=null, 5xx/네트워크): 본문 전체를 danger
Banner(hq-library-detail-error)로 대체 — 트랙 query 는 비활성(enabled:!!id, 불필요 호출 회피).
격리 (D2 — #080 §D3 일관)
라이브러리는 hqId 컬럼이 없는 운영사 공유 모델이다. verifyHqScope(403 가드 — ACTIVE·
HQ_MANAGER·hqId 일치)만 통과하면 모든 활성 라이브러리 상세를 조회할 수 있다. PL 상세(#057)의
hqId != → 404 은닉 분기를 넣지 않는다. 활성 라이브러리 미존재/soft-deleted → 404
LIBRARY_NOT_FOUND → server 가 Next notFound() 로 분기.
사이드바
HQSidebar 의 “라이브러리”(/admin/libraries) 항목이 enabled(활성 라우팅) — #080 에서
disabled “준비 중”(이전 placeholder href /admin/library)에서 전환. SPEC 경로로 통일하면서
href 도 /admin/library → /admin/libraries 로 정렬.
인가
GET /api/v1/hq/libraries → hasRole("HQ_MANAGER") 1차 경계 + service verifyHqScope claim↔DB
재검증(#049/#057 재사용). 미인증 401 · 비활성/role·소속 불일치 403 PRINCIPAL_SCOPE_MISMATCH.
목록 fetch 는 generated apiFetch 가 BFF catch-all /api/backend/... 경유(토큰 서버 전용).
Followups
F1 라이브러리 상세 view✅ SPEC #107 — 메타 카드 + 소속 음원(트랙) 목록 read-only (/admin/libraries/[id]). 위 상세 섹션 참조.- F2 본사 PL → 라이브러리 추가 다이얼로그 — 운영사 PL edit 패턴 미러(권한은 본사 PL 에 한정).
- F3 plan/type mismatch 게이트 — #060 F1 와 짝.