DomainEnums

Enums (도메인 enum 카탈로그)

Kotlin enum (backend) + TypeScript const enum / union (frontend packages/api-client/src/generated/). 모두 @Enumerated(EnumType.STRING) 저장 — 가독성 + migration 안전.

HqType

의미
FRANCHISE프랜차이즈 본부. 산하에 DIRECT/FRANCHISE 매장. plan, billingAnchorDay NOT NULL.
INDEPENDENT가상 본사. 시스템 전체 1개 (partial unique). 개인 매장 (INDEPENDENT type) 산하. plan = NULL, billing 모두 NULL.

HqStatus

현재 도입 완료 — BE v0.7.0 (SPEC #013) Flyway V7. 4 종 enum. generated 스키마 HqAdminListItemStatus. 정지/복구 전이는 SPEC #018 (BE v0.11.0) 도입 완료 — suspend/reactivate endpoint + hq-list 액션. 자동 전환·사유 저장은 후속.

의미비고
ACTIVE정상 운영임퍼소네이션 가능 (FRANCHISE 한정) · 가상 본사는 이 값 고정 · 정지 대상
ONBOARDING초기 등록 후 활성화 전신규 본사 default · 정지 대상
UNPAID결제 미납UI 경고 (배경 색 변경) · 정지 대상
SUSPENDED협약 위반 / 운영사 정지임퍼소네이션 confirm 비활성 · 관리자 세션 무효화 + 로그인 차단 · 복구(reactivate)로만 ACTIVE 복귀

전이: ACTIVE \| ONBOARDING \| UNPAID → SUSPENDED (suspend) · SUSPENDED → ACTIVE (reactivate). INDEPENDENT 가상 본사는 전이 불가. 상세는 Status Lifecycle.

StoreType

의미결제 단위
DIRECT직영 매장HQ
FRANCHISE가맹 매장HQ
INDEPENDENT개인 매장Store

StoreStatus

의미자동 전환
ACTIVE정상default
SUSPENDED정지 (운영사 액션, #037)수동 — ACTIVE|INACTIVE → SUSPENDED
INACTIVE90일 미사용스케줄러 (FR-11.10, 후속)

SPEC #019 매장 목록(/stores) 의 StoreAdminListItemStatus(generated) 와 정합: ACTIVE · INACTIVE · SUSPENDED. StoreAdminListItemTypeINDEPENDENT · DIRECT · FRANCHISE 로 위 StoreType 과 일치. SPEC #037 정지/복구 전이 도입 — suspend(ACTIVE\|INACTIVE→SUSPENDED)·reactivate(SUSPENDED→ACTIVE). 상세는 Status Lifecycle 참고.

PlanType

의미라이브러리
AI자체 음원 onlyAI 라이브러리
TRUSTAI + 신탁음원AI + TRUST 라이브러리

Role

의미hqIdstoreId
OPERATOR운영사NULLNULL
HQ_MANAGER본사 관리자NOT NULLNULL
STORE_MANAGER점장NULLNOT NULL

도메인 invariant — entity 생성자 require(...).

  • HQ_MANAGER 는 본사 온보딩(POST /api/v1/admin/hq, #010)에서 발급된다.
  • STORE_MANAGER 는 매장 생성과 분리해 POST /api/v1/admin/stores/{storeId}/managers(#021)로 사후 발급한다 — storeId tenancy, hqId=null, passwordMustChange=true. 매장당 복수 발급 가능(하드 블록 없음). 운영사 매장 목록(/stores)이 StoreAdminListItem.hasManagerAccount 로 발급 여부를 표시한다.

AccountStatus

의미
ACTIVE정상
SUSPENDED로그인 차단 (정지 — 즉시 세션 무효화)
WITHDRAWN회수/탈퇴 (soft-delete, terminal — 이메일 재사용 불가)

STORE_MANAGER 계정은 SPEC #029 로 전이 액션이 도입됐다(ACTIVE ↔ SUSPENDED, ACTIVE/SUSPENDED → WITHDRAWN). generated 노출 enum StoreManagerListItemStatus = 같은 3값. 상세 전이·효과는 Status Lifecycle 참고.

HqAffiliatedStoreType (현재 미도입, 후속)

값 (예정)의미
DIRECT_ONLY직영만
FRANCHISE_ONLY가맹만
MIXED직영 + 가맹 혼합

본사의 매장 구성 형태. 현재는 type 별 store row count 로 유추.

ImpersonationTokenStatus (현재 entity 컬럼 없음, 상태는 used_at 으로 유추)

의미
활성 (60초 이내, used_at = NULL)
만료 (expires_at < now())
사용됨 (used_at != NULL)

TicketStatus (#027 — CS 티켓)

의미tone(FE)
OPEN열림 (생성 직후)info
IN_PROGRESS처리 중warn
RESOLVED해결됨success
CLOSED닫힘muted

전이 규칙은 status-lifecycle 참고 (OPEN → IN_PROGRESS → RESOLVED → CLOSED

  • 재오픈 RESOLVED/CLOSED → IN_PROGRESS). 잘못된 전이는 backend 409 TICKET_INVALID_STATUS_TRANSITION.

TicketPriority (#027 — CS 티켓)

의미색점 tone(FE, 임시)
URGENT긴급danger
HIGH높음warn
NORMAL보통info
LOW낮음muted

v1 — 우선순위는 생성 시점에만 설정(변경 endpoint 없음). 색점은 전용 시안 부재로 기존 StatusPill tone 만 재사용한 임시 레이아웃.

CommentKind (#027 — CS 티켓 코멘트)

의미
REPLY고객 응답 (외부 노출 톤)
INTERNAL내부 메모 (내부 통제용 톤)

LegalDocumentStatus (#033 — 약관·개인정보 게시본 상태)

의미FE StatusPill 톤
SCHEDULED예약 — effectiveAt 가 미래(아직 발효 전)info
ACTIVE게시 시점 유효 (즉시 게시·발효됨)success
SUPERSEDED대체됨 (이후 버전에 의해)muted

generated 노출 enum LegalDocumentResponseStatus·LegalDocumentHistoryItemStatus = 같은 3값. stale 주의: 스케줄러가 없어 status 는 게시 시점 스냅샷이다. 예약본이 발효 시각을 지나도 SCHEDULED 로 남을 수 있으므로, “현재 유효본” 판정은 effectiveAt (<= now 중 최신)으로 한다. /active 응답은 status 를 항상 ACTIVE 로 보정. 상세는 Status Lifecycle.

OperatorAuditAction (#026 — 운영자 액션 감사 로그 액션 종류)

운영자 핵심 변경 액션의 append-only 감사 로그 액션 enum. generated 노출 enum OperatorAuditItemAction(/audit/actions). 신규 액션은 VARCHAR 영속이라 마이그레이션 무관.

의미FE StatusPill 톤도입
HQ_SUSPENDED / HQ_REACTIVATED본사 정지 / 복구danger / success#018·#024
HQ_UPDATED본사명 편집 (운영사 전용)info#123
STORE_SUSPENDED / STORE_REACTIVATED매장 정지 / 복구danger / success#037
STORE_CLOSED매장 폐점 (비가역 terminal)danger#039
STORE_MANAGER_ISSUED점장 발급info#021
STORE_MANAGER_PASSWORD_RESET점장 비밀번호 재설정muted#029
STORE_MANAGER_SUSPENDED / STORE_MANAGER_REACTIVATED / STORE_MANAGER_REVOKED점장 정지 / 복구 / 회수warn / success / danger#029
OPERATOR_ISSUEDOPERATOR_REVOKED (5종)운영자 초대·재설정·정지·복구·회수info·muted·warn·success·danger#032
TERMS_PUBLISHED / PRIVACY_POLICY_PUBLISHED약관 / 개인정보 게시playing#033
TERMS_SCHEDULE_CANCELED / PRIVACY_POLICY_SCHEDULE_CANCELED약관 / 개인정보 예약 취소warn#038
MUSIC_UPLOADED음원 업로드info#041
MUSIC_FILE_REPLACED음원 파일 교체warn#041
MUSIC_DELETED음원 소프트삭제 (deleted_at 채움, blob 유지)danger#042
TICKET_STATUS_CHANGED티켓 상태 변경info#047
TICKET_ASSIGNED티켓 담당자 배정 / 해제 (단일 액션, detail 분기)info#047
TICKET_PRIORITY_CHANGED티켓 우선순위 변경warn#047
HQ_ONBOARDED본사 온보딩playing

대상 타입(OperatorAuditItemTargetType): HQ · STORE · OPERATOR · TERMS · PRIVACY_POLICY · MUSIC(#041) · TICKET(#047). 매장 정지/복구/폐점의 targetType = STORE, targetId = storeId, targetLabel = 매장명, detail = 사유(suspend/close). 음원 업로드/교체의 targetType = MUSIC, targetId = 음원 PK, targetLabel = 곡 제목 스냅샷, detail = 원본 파일명·크기(#041). 음원 소프트삭제(MUSIC_DELETED)의 targetType = MUSIC(재사용), targetId = 음원 PK, targetLabel = 곡 제목 스냅샷(#042). 티켓 상태/우선순위/담당자 변경의 targetType = TICKET, targetId = 티켓 PK, targetLabel = 티켓 title 스냅샷. detail 은 상태/우선순위 이전→이후(예 OPEN→IN_PROGRESS·HIGH→URGENT), 담당자 배정: {email}(이메일) / 해제(#047).

MusicSource (#059 — 음원 타입)

음원의 출처 타입. 업로드 시 지정·불변. 라이브러리 타입(libraryType)과 동일 도메인으로, 음원을 라이브러리에 담을 때 musicSource == libraryType 이어야 한다(불일치 시 400 LIBRARY_TYPE_MISMATCH). generated 노출 enum MusicListItemMusicSource / MusicResponseMusicSource / UploadMusicMusicSource / ListMusicMusicSource. FE 는 MUSIC_SOURCE_META 단일 소스로 라벨/톤을 매핑하며 라이브러리 타입 배지와 동일 표현(색만으로 구분하지 않고 라벨 병기).

의미FE StatusPill 톤
AIAI 생성 음원info
TRUST신탁 음원playing

플랜(PlanType)의 AI/TRUST 는 본사 구독 등급, 음원의 musicSource개별 음원의 출처 타입으로 의미 레이어가 다르다(라벨만 공유). 라이브러리·플랜·음원의 AI/TRUST 표현은 톤/라벨을 일관 유지한다.

MusicTagOptionType (#132 — 음원 태그 옵션 타입)

음원 분류 태그 옵션(music_tag_option)의 타입. 생성 후 불변. 같은 타입 내 value 는 unique (중복 시 409 MUSIC_TAG_OPTION_DUPLICATE). generated 노출 enum MusicTagOptionResponseType / CreateMusicTagOptionRequestType / ListMusicTagOptionsType(모두 동일 2값). FE /settings/music-options 는 타입별로 2 섹션(장르·무드)을 분리해 렌더한다.

의미
GENRE장르 (예: 재즈·힙합·클래식)
MOOD무드 (예: 차분한·신나는·잔잔한)

라이브러리·플레이리스트 분류에 쓰일 태그 옵션의 마스터 데이터. 운영사가 CRUD 로 관리하며 삭제는 soft delete(active=false). 음원 업로드 폼이 이 옵션을 소비(드롭다운)하는 연동은 후속.

PlaylistStatus (#060 — 플레이리스트 파생 상태)

플레이리스트의 파생(계산) 상태. DB 컬럼·마이그레이션 없는 응답 계산값으로, BE 단일 함수 derivePlaylistStatus(libraryCount, appliedStoreCount, isDefault)(운영사·본사 서비스 공유)가 집계로 판정한다. 한 PL 은 정확히 1개 상태이며 배타적 우선순위로 결정한다. generated 노출 enum PlaylistResponseStatus / PlaylistListItemStatus / HqPlaylistListItemStatus / HqPlaylistDetailResponseStatus(모두 동일 4값). FE 는 표시만 하며(서버 파생값 신뢰) playlist-status-meta.ts 단일 소스로 라벨/톤을 매핑한다(운영사·본사 일치·라벨 항상 병기).

우선순위판정 조건FE 라벨FE StatusPill 톤
1EMPTYlibraryCount == 0 (라이브러리 미보유, 최우선)비어있음warn
(2)(MISMATCH)플랜 불일치 — PL 상태 배지는 아직 미구현(후속). #122 는 점장 큐 게이팅만 도입
3FALLBACKisDefault == true (본사 기본 PL·점장 큐 fallback 대상)기본info
4ACTIVEappliedStoreCount >= 1 (적용 매장 있음)사용 중success
5UNUSED그 외 (libraryCount>0 && !isDefault && appliedStoreCount==0)미사용muted

상태 모델은 5종 설계(EMPTY/MISMATCH/FALLBACK/ACTIVE/UNUSED)이나 PL 상태 배지는 비게이트 4종만 구현한다. SPEC #122(#060 F1)는 plan↔type 게이팅의 첫 구현이나, 운영사/본사 PL 화면의 MISMATCH 배지가 아니라 점장 재생 큐에서 plan 위반 음원을 서버가 제외하는 게이팅만 도입한다(effective plan=store.plan ?? hq.plan vs library.libraryType, plan null=무제약, 전부 위반→EMPTY_PLAYLISTStore Player §“플랜 위반 음원 큐 제외”). PL 상태 배지로서의 MISMATCH(운영사/본사 편집 화면 경고)는 여전히 후속 — 도입 시 우선순위에서 EMPTY 다음·FALLBACK 앞에 들어갈 예정. FALLBACK status 는 기존 isDefault “기본” 배지와 라벨이 겹치므로 FE 는 status 배지로 통합하고 별도 기본 배지를 숨긴다(status≠FALLBACK 인 기본 PL 은 병치 — 상세는 Playlist · HQ Mode 플레이리스트).

TtsVoice (#061 — TTS 안내방송 voice)

본사 TTS 안내방송 합성에 쓰는 voice. 5종. BE TtsVoice enum 이 actor_id·model_version·표시명을 내부 보유하고, API 에는 enum name + 한글 표시명만 노출(actor_id 비노출). generated 노출 enum CreateTtsAnnouncementRequestVoice / TtsAnnouncementListItemVoice / TtsAnnouncementDetailResponseVoice (모두 동일 5값). 목록·상세는 BE voiceDisplayName(한글)을 단일 소스로 표시한다. 생성 폼만 합성 전이라 BE 표시명을 받을 수 없으므로 FE tts-voice-meta.ts 가 value→한글 라벨을 보유(라벨 어긋나도 합성은 enum value 로 진행 — 안전).

FE 생성 폼 라벨(예시)
SHEAN시안 (차분한 여성)
WOOSUNG우성 (안정된 남성)
CYRUS사이러스 (밝은 남성)
AERAN애란 (따뜻한 여성)
SEUNGA승아 (또렷한 여성)

voice별 tone preset 선택 — #063 도착(아래 TtsTonePreset). FE 생성 폼 라벨은 BE TtsVoice.displayName 과 정합을 유지한다(BE 가 응답 voiceDisplayName 의 단일 소스).

TtsTonePreset (#063 — TTS 안내방송 톤 프리셋)

본사 TTS 안내방송 합성의 감정 톤(Typecast emotion). 6종. voice별 지원 집합이 다르며 모든 voice 가 NORMAL(기본) 을 지원한다. BE TtsTonePreset enum 이 Typecast emotion 파라미터·표시명을 내부 보유하고, API 에는 enum name + 한글 표시명(*DisplayName)만 노출. generated 노출 enum CreateTtsAnnouncementRequestTonePreset(@nullable) / UpdateTtsAnnouncementRequestTonePreset(@nullable) / TtsAnnouncementListItemTonePreset / TtsAnnouncementDetailResponseTonePreset / TtsTonePresetOptionPreset (모두 동일 6값). voice별 허용 매핑은 GET /api/v1/hq/tts-voices(TtsVoiceListResponse)가 단일 소스.

FE 폴백 라벨(예시)
NORMAL기본
HAPPY밝게
TONEUP톤 업
TONEDOWN톤 다운
ANGRY강하게
SAD차분하게

톤 표시명은 BE tonePresetDisplayName(voices 응답·목록·상세)이 단일 소스다. FE 는 voices 응답이 아직/실패일 때의 폴백 라벨만 tts-voice-meta.ts 에 보유(NORMAL 만 노출). 생성·수정 폼은 선택 voice 의 허용 톤만 옵션으로 보이고, voice 미지원 톤은 UI 가 차단(혹시 도달 시 BE 400 TTS_INVALID_TONE_PRESET).

DispatchRequestTarget (송출 슬라이스 — 안내방송 송출 대상)

본사 안내방송 송출(POST /api/v1/hq/announcements/{id}/dispatch) + 반복 예약 (POST /api/v1/hq/dispatch-schedules)의 대상 구분. 3종 (SPEC #144 REGION 추가). generated DispatchRequestTarget(DispatchRequest.target) / CreateDispatchScheduleRequestTarget / DispatchScheduleResponseTarget.

의미
ALL산하 매장 전체. storeIds·region 무시. (매장 0건이면 dispatchedCount=0)
STORES지정 매장. storeIds 필수(≤1000, 모두 본인 본사 산하). 비어있거나 타 본사 → 400 DISPATCH_INVALID_TARGET
REGION(SPEC #144) 지정 지역(Region 시/도). region 필수(누락 시 400 DISPATCH_REGION_REQUIRED). service 가 hqId AND region=:region 매장으로 fan-out(해당 region 매장 0건이면 dispatchedCount=0)

ALL/STORES/REGION 분기는 즉시 송출·반복 예약 양쪽에서 동일. FE 는 송출/예약 다이얼로그 target 라디오에 “지역” 옵션 + region select(시/도) 를 노출하고, target=REGION 인데 미선택이면 제출 disabled(BE 400 선검증). 상세는 HQ TTS 안내방송 송출.

Region (SPEC #144 — 매장 지역 시/도)

매장(Store.region, nullable)의 시/도 enum. REGION 모드 송출의 그룹핑 축. 17종. 본사가 매장 상세에서 태그하면 target=REGION 으로 같은 시/도 매장군에 일괄 송출한다. BE Region enum 이 displayName(한글)을 내부 보유하고, OpenAPI 에는 enum name 만 노출 → FE 는 한글 라벨 맵을 apps/space/src/lib/region.ts 에 단일 소스로 보유(generated 의 per-field region enum 17값을 value 소스로 재사용). generated 노출 enum: UpdateStoreRegionRequestRegion / HqStoreDetailResponseRegion / DispatchRequestRegion / CreateDispatchScheduleRequestRegion / DispatchScheduleResponseRegion(모두 동일 17값, nullable).

enum name라벨enum name라벨
SEOUL서울GANGWON강원
BUSAN부산CHUNGBUK충북
DAEGU대구CHUNGNAM충남
INCHEON인천JEONBUK전북
GWANGJU광주JEONNAM전남
DAEJEON대전GYEONGBUK경북
ULSAN울산GYEONGNAM경남
SEJONG세종JEJU제주
GYEONGGI경기

Store.regionnull(미지정)이면 지역 송출에 포함되지 않는다. 편집은 본사 매장 상세 매장 지역 편집 참고. 자동 주소 파싱 채움은 범위 밖(수동 선택).

DispatchStatus (송출 슬라이스 — 안내방송 송출 상태)

송출 row(announcement_dispatch.status)의 생명주기. 5종 (SPEC #077 CANCELED 추가 + SPEC #078 SCHEDULED 추가 + SPEC #143 MISSED 추가). 전이는 단방향SCHEDULED → PENDING → PLAYED(정상 경로) · SCHEDULED → CANCELED(예약 직접 취소) · PENDING → CANCELED(즉시/예약-전이된 PENDING 취소) · PENDING → MISSED(도래+grace 10분 초과 자동 만료, SPEC #143). PLAYED·CANCELED·MISSED 는 종착 상태(이후 전이 없음 — 시간 되감기 X · 중복 취소 가드).

SCHEDULED ──┬──> PENDING ──┬──> PLAYED
            │              ├──> MISSED   (도래+grace 10분 초과·미재생)
            └──> CANCELED <─┘
의미
SCHEDULED(SPEC #078) 예약 송출 row 의 초기 상태. 본사가 미래 scheduledAt 으로 송출 요청 시 적재됨. 백그라운드 디스패처(HqDispatchScheduler, @Scheduled(cron='0 * * * * *'))가 도래 시 원자 UPDATE(WHERE status='SCHEDULED' AND scheduled_at <= :now) 로 PENDING 전이. 점장 player 는 WHERE status='PENDING' 만 폴링하므로 SCHEDULED 는 자연 제외
PENDING송출 직후 기본값(즉시 송출) 또는 디스패처가 SCHEDULED 에서 전이한 상태. 점장 player 의 pending 폴링 대상(listStorePendingAnnouncements)
PLAYED점장이 재생 완료 ack(ackStoreAnnouncement). BE 는 원자 조건부 UPDATE(WHERE status='PENDING') — 첫 ack 만 204, 중복 ack·이미 PLAYED·타 매장·미존재는 모두 404 DISPATCH_NOT_FOUND(상태·존재 은닉). 효과는 멱등(상태 불변)이나 응답은 404
CANCELED본사가 PENDING 또는 SCHEDULED(SPEC #078) dispatch 를 취소(cancelHqDispatch, SPEC #077·#078). 원자 조건부 UPDATE(WHERE id AND hq_id AND (status='PENDING' OR status='SCHEDULED')) — 1행 영향 시 204, 0행(이미 PLAYED·CANCELED·미존재·타 본사)은 모두 404 DISPATCH_NOT_FOUND(상태·존재 은닉). 점장 pending 조회는 WHERE status='PENDING' 만 매치하므로 CANCELED 자동 제외(별도 cleanup 0). 같은 트랜잭션에 본사 audit 1건(HQ_ANNOUNCEMENT_DISPATCH_CANCELED) 기록. 원격 즉시중단(revoke)도 CANCELED 로 전이(revokeHqDispatch, SPEC #077 확장 — PENDING-only + revoked_at set + audit HQ_DISPATCH_REVOKED, 점장 player 가 revokedDispatchIds 신호로 재생 중 멘트 즉시 중단)
MISSED(SPEC #143) PENDING 이 도래 시각 + grace(10분) 을 초과해도 재생 ack 가 없으면 디스패처가 자동 만료시킨 종착 상태. 백그라운드 디스패처가 원자 UPDATE(WHERE status='PENDING' AND created_at <= :now - grace)로 MISSED 전이(점장이 늦게 ack 하면 race 로 PLAYED 가 이기거나 404). 점장 pending 조회는 WHERE status='PENDING' 만 매치하므로 MISSED 자동 제외 — 만료 후엔 player 에 더 노출되지 않는다. 통계에선 송출 상태 분포에 집계되나 도달률 분모(PENDING+PLAYED)에선 제외(재생 시도분이 아닌 미재생 만료라). 별도 audit 없음(시스템 자동 만료)

상세는 AnnouncementDispatch 테이블 · Store Player 삽입 재생 · 본사 송출 취소.

DispatchCalendarEventKind / DispatchCalendarEventStatus (송출 캘린더)

송출 캘린더(GET /api/v1/hq|store/dispatch-calendar, DispatchCalendarEvent)의 이벤트 분류 enum. 본사·점장 공용.

DispatchCalendarEventKindis_emergency·is_hq_origin 에서 파생.

의미
EMERGENCY긴급 안내(최우선). FE 캘린더는 status 무관 danger 톤으로 강조
HQ_ANNOUNCEMENT본사 안내방송 송출
STORE_BROADCAST점장 매장 방송 송출

DispatchCalendarEventStatusDispatchStatus 와 동일 4종(SCHEDULED → PENDING → {PLAYED, CANCELED} 단방향). FE 캘린더 톤: SCHEDULED/PENDING=info, PLAYED=success, CANCELED=muted(취소선, “MISSED=muted” 의도 대응).

상세는 DispatchCalendarResponse DTO · 본사 캘린더 · 점장 캘린더.

DispatchScheduleFrequency (반복 송출 예약 — 빈도, #139 확장)

본사 반복 송출 예약(dispatch_schedule.frequency)의 빈도. 5종 (#139 — 시각형 HOURLY·EVEN_HOURS· ODD_HOURS 추가, 기존 DAILY·WEEKLY 보존). generated CreateDispatchScheduleRequestFrequency / DispatchScheduleResponseFrequency(동일 값). FE radiogroup·라벨(dispatch-schedule-meta.ts FREQUENCY_LABELS)·타임테이블 전개(expandOperatingHours)가 이 enum 단일 소스를 재사용한다.

의미연관 필드
DAILY매일 1회slotTime(HH:MM). byWeekday·startHour·endHour 무시
WEEKLY지정 요일마다 1회byWeekday(요일 CSV, 필수) + slotTime(HH:MM)
HOURLY운영시간 매 정시마다startHour·endHour(0-23, start≤end, 필수) + slotTime 의 분(MM)만 매시 :MM 오프셋(시 무시)
EVEN_HOURS운영시간 내 짝수 hour마다위와 동일
ODD_HOURS운영시간 내 홀수 hour마다위와 동일

시각형(HOURLY/EVEN_HOURS/ODD_HOURS)은 startHour·endHour(운영시간)가 필수이며 slotTime 의 시(HH)는 무시된다(분 MM만 매시 오프셋). 빈도↔요일·빈도↔운영시간 불일치·범위 위반은 400 DISPATCH_SCHEDULE_INVALID. 백그라운드 디스패처가 시각형이면 하루 N건(운영시간 hour마다)으로 전개한다. 상세는 반복 송출 예약.

TtsAnnouncementSource (즉시방송 슬라이스 — 안내방송 출처)

tts_announcement.source(V24)의 출처 구분. 2종. 같은 테이블을 본사 안내방송과 점장 즉시방송이 공유하되 source 로 격리한다.

의미
HQ본사(HQ_MANAGER)가 만든 안내방송. 기존 행 backfill 기본값. 본사 화면(목록·상세·수정·삭제·dispatch)이 다루는 유일한 source
STORE_BROADCAST점장(STORE_MANAGER)이 즉시방송 미리듣기(previewStoreBroadcast)로 만든 draft. created_by_store_id 채워짐. send 로 본인 매장에만 dispatch

보안 불변식 — 본사-facing 쿼리는 모두 source='HQ' 로 격리해 STORE_BROADCAST row 가 본사 화면·계약에 노출되지 않는다. 점장 즉시방송 흐름은 점장 즉시방송 · TtsAnnouncement 테이블.

HqAuditAction (#067 도입 · #068 확장 — 본사 감사 액션)

hq_audit_log.action(V27)의 본사(HQ_MANAGER) 액션 enum. 현재 4종(SPEC #068 에서 라이프사이클 3종 추가). generated FE 도메인은 HqAuditItemAction·ListHqAuditDispatchesAction(value 동일).

의미
HQ_ANNOUNCEMENT_DISPATCHED본사 안내방송 송출. HqAnnouncementDispatchService.dispatch 트랜잭션 내 1행 기록 — actor·시각·target=ALL|STORES·count·storeIds(앞 10개) 스냅샷
HQ_ANNOUNCEMENT_CREATED본사 안내방송 생성. HqTtsAnnouncementService.create 트랜잭션 내 1행 — title·voice·tonePreset·durationSeconds(null = “null” 명시) 스냅샷
HQ_ANNOUNCEMENT_UPDATED본사 안내방송 수정. HqTtsAnnouncementService.updatetitle·voice·tonePreset·resynthesized(text/voice/tonePreset 변경 시 true) 스냅샷. no-op(모든 필드 동일) 시 audit 미기록(early return)
HQ_ANNOUNCEMENT_DELETED본사 안내방송 soft-delete. HqTtsAnnouncementQueryService.deletetitle 스냅샷(삭제된 안내방송 식별)
HQ_ANNOUNCEMENT_DISPATCH_CANCELED본사 송출 취소(SPEC #077). cancelHqDispatch 트랜잭션 내 1행 — PENDING/SCHEDULED dispatch CANCELED 전이
HQ_DISPATCH_REVOKED본사 송출 원격 즉시중단(SPEC #077 확장). revokeHqDispatch 트랜잭션 내 1행 — PENDING dispatch CANCELED 전이 + revoked_at set. cancel(재생 전 무효화)과 별도 audit 액션으로 운영 의도 구분(revoke=재생 중/직전 best-effort 중단, 점장 player 가 revokedDispatchIds 신호로 즉시 멈춤)
HQ_STORE_REGION_UPDATED본사 매장 지역(시/도) 변경(SPEC #144). updateStoreRegion 트랜잭션 내 1행 — targetType=STORE, before/after region 스냅샷. FE audit 뷰 라벨 “매장 지역 변경”(info 톤)

generated 도메인(HqAuditItemAction·ListHqAuditDispatchesAction)에는 추가 액션(ticket·store·반복 예약 등)도 포함된다 — 위는 안내방송 송출 라이프사이클 핵심 액션 + #144 지역 변경. Followups: 점장 즉시방송 audit 은 별도 enum/테이블(F3 — store_audit_log). 상세는 HqAuditLog · HQ Mode 감사.

HqAuditActorRole (#067 — 본사 감사 행위자 역할)

hq_audit_log.actor_role(V27). 2종. impersonate 컨텍스트 구분 — impersonated_by_operator_id 컬럼과 정합성을 CHECK 제약으로 강제한다((actor_role='OPERATOR_IMPERSONATING') = (impersonated_by_operator_id IS NOT NULL)). generated FE 도메인은 HqAuditItemActorRole(value 동일).

의미
HQ_MANAGER본사 매니저 직접 송출(임퍼소네이션 아님). impersonated_by_* 컬럼 null
OPERATOR_IMPERSONATING운영자(principal.impersonatedBy != null)가 본사로 위장해 송출. impersonated_by_operator_id/email 동시 기록 — 원본 운영자와 위장 본사 매니저 둘 다 추적

impersonate 미러 — principal.accountId = HQ_MANAGER 계정(actor_account_id), principal.impersonatedBy = 원본 운영자(impersonated_by_operator_id). 둘 다 lookup 실패 시 IllegalStateException → 액션 롤백. 상세는 HqAuditLog.

HqAuditTargetType (#067 — 본사 감사 대상 유형)

hq_audit_log.target_type(V27)의 대상 유형 enum. 현재 1종(후속 SPEC 으로 확장). generated FE 도메인은 HqAuditItemTargetType(value 동일).

의미
TTS_ANNOUNCEMENT본사 TTS 안내방송(tts_announcement.id). target_id=안내방송 id, target_label=제목 스냅샷

Followups: 후속 액션 확장에 따라 대상 유형도 추가 가능(예: announcement create/update/delete 도 같은 유형). 상세는 HqAuditLog · HQ Mode 감사.

StoreAuditAction (#114 — 매장 감사 액션)

store_audit_log.action(V36)의 점장(STORE_MANAGER) 액션 enum. 현재 8종(HqAudit 처럼 점진 확장 — 새 점장 액션은 VARCHAR(48) 영속이라 마이그레이션 무관). HqAuditAction· OperatorAuditAction 과 의미가 분리된 별도 enum (actor·테넌트 스코프·UI 권한 모델이 다름). v1 은 기록만이라 generated FE 도메인 노출은 조회 view 후속에서.

의미
STORE_TICKET_CREATED점장 CS 티켓 생성 (#112 audit tail 마감). StoreTicketService.createStoreTicket — target_id=ticket.id·target_label=ticket.title·detail=title=...·category=NAME·bodyLength=N 스냅샷
STORE_TICKET_COMMENT_ADDED점장 CS 티켓 댓글 추가 (#112). StoreTicketService.addStoreTicketComment — target_id=ticket.id(댓글 id 아님 — audit 는 ticket scope)·detail=bodyLength=N
STORE_TICKET_CLOSED점장 CS 티켓 확인 종료 RESOLVED→CLOSED (#121). StoreTicketService.closeStoreTicket — target_type=SUPPORT_TICKET·target_id=ticket.id·target_label=ticket.title 스냅샷. store_id 격리 원자 UPDATE affected=1 확정 시에만 기록(409/404 분기 후)
STORE_PROFILE_UPDATED점장 본인 매니저 계정 name 편집 (#087 F4 마감). StoreMeService.updateMe — target_type=STORE_MANAGER·detail=changedFields=name·name:before->after. 변경 0(멱등 no-op) 시 audit 미기록
STORE_PASSWORD_CHANGED점장 본인 비밀번호 변경 (#100 F2 마감). 공용 AuthService.changePassword role=STORE_MANAGER 분기 — target_type=STORE_MANAGER·detail 없음(보안 — 비밀번호·길이 미기록)·임퍼소네이션 차단되어 actor 항상 본인
STORE_DISPATCH_CANCELED점장 본인 매장 예약 송출 취소 (#092 F2 마감). StoreBroadcastService — SCHEDULED dispatch 를 CANCELED 로 단방향 전이·target_type=DISPATCH·detail 없음(원자 UPDATE affected=1 확정 시에만 기록)
STORE_ACTIVE_PLAYLIST_CHANGED점장 본인 매장 활성 PL 선택·해제 (#129). 활성 PL 지정(playlistId) 또는 본사 기본 fallback(null) 로 실제 변경 시·target_type=PLAYLIST. 기존 운영사/본사 활성 PL 지정 로직 재사용
STORE_DISPATCH_BROADCAST_NOW점장 예약 송출 즉시 방송 (#142). StoreBroadcastService — SCHEDULED dispatch 의 안내방송으로 새 IMMEDIATE dispatch 1건 생성(원본 SCHEDULED 무변경)·target_type=DISPATCH·target_id=새 IMMEDIATE dispatch.id·detail = 원본 SCHEDULED dispatch.id 스냅샷(sourceScheduledDispatchId) — 즉시 방송이 어느 예약본에서 비롯됐는지 역추적용

Followups: 점장 액션 도착 시 enum 확장. v1 은 기록만 — 조회 view(운영자/본사) 는 후속(D5). 상세는 StoreAuditLog · Store 감사.

StoreAuditActorRole (#114 — 매장 감사 행위자 역할)

store_audit_log.actor_role(V36). 2종. HqAuditActorRole 미러 — impersonate 컨텍스트를 구분하고 impersonated_by_operator_id 컬럼과 정합성을 CHECK 제약으로 강제한다 ((actor_role='OPERATOR_IMPERSONATING') = (impersonated_by_operator_id IS NOT NULL)).

의미
STORE_MANAGER점장 본인이 직접 액션(임퍼소네이션 아님). impersonated_by_* 컬럼 null
OPERATOR_IMPERSONATING운영자(principal.impersonatedBy != null)가 점장 모드로 위장해 액션. impersonated_by_operator_id/email 동시 기록 — 원본 운영자와 위장 점장 둘 다 추적

impersonate 미러 — principal.accountId = 점장 계정(actor_account_id), principal.impersonatedBy = 원본 운영자(impersonated_by_operator_id). 둘 다 lookup 실패 시 IllegalStateException → 액션 롤백. 상세는 StoreAuditLog.

StoreAuditTargetType (#114 — 매장 감사 대상 유형)

store_audit_log.target_type(V36)의 대상 유형 enum. 현재 4종(ASCII 사전순). 후속 액션 확장에 따라 추가 가능.

의미
DISPATCH예약 송출(announcement_dispatch.id). STORE_DISPATCH_CANCELED·STORE_DISPATCH_BROADCAST_NOW(#142) 의 대상
PLAYLIST플레이리스트(playlist.id). STORE_ACTIVE_PLAYLIST_CHANGED(#129) 의 대상
STORE_MANAGER점장 본인 매니저 계정(self, 점장 계정 id). STORE_PROFILE_UPDATED·STORE_PASSWORD_CHANGED 의 대상
SUPPORT_TICKETCS 티켓(ticket.id·target_label=title 스냅샷). STORE_TICKET_CREATED·STORE_TICKET_COMMENT_ADDED 의 대상

상세는 StoreAuditLog · Store 감사.

OpenAPI 동기화

backend enum 변경 시 pnpm sync-apipackages/api-client/src/generated/ 의 TypeScript union / const enum 자동 갱신. 수기 정의 금지 (frontend [[feedback-15]] 정합).

References

  • SPEC #002 §2-3 (HqType · StoreType · PlanType · StoreStatus)
  • SPEC #003 §2-1 (Role · AccountStatus)
  • SPEC #005 (ImpersonationToken)
  • linkmusic-msa-space-was/src/main/kotlin/.../domain/enum/
  • linkmusic-frontend-space/packages/api-client/src/generated/schemas/