diff --git a/docs/history.md b/docs/history.md index 4d26fd6..d073629 100644 --- a/docs/history.md +++ b/docs/history.md @@ -1,5 +1,9 @@ # 의사결정 이력 +## 2026-04-02 v1.4.0 +- 서비스가 게임 외 주제 전반을 다룰 수 있는 단계에 온 만큼, 내부 모델명은 유지하더라도 사용자에게 보이는 주요 용어는 `주제 / 템플릿` 기준으로 먼저 정리하는 편이 맞다고 판단했다. +- 대규모 내부 리네이밍은 API와 DB까지 손대야 하므로, 이번 단계에서는 사용자 화면 문구만 우선 바꾸고 내부 `game` 모델은 그대로 두는 점진적 전환이 더 안전하다고 정리했다. + ## 2026-04-02 v1.3.93 - 목록 카드 썸네일은 드래그 대상이 아니라 클릭 대상에 가깝기 때문에, 브라우저 기본 이미지 드래그 프리뷰는 전부 막아 두는 편이 UX 측면에서 맞다고 판단했다. diff --git a/docs/todo.md b/docs/todo.md index e208d3d..bf224fc 100644 --- a/docs/todo.md +++ b/docs/todo.md @@ -1,6 +1,8 @@ # 할 일 및 이슈 ## 단기 확인 +- 용어 정리 1차는 사용자 노출 문구만 `주제 / 템플릿`으로 바꿨으므로, 홈/주제 화면/관리자 템플릿 관리에서 어색하게 남은 `게임` 문구가 없는지 한 번 더 QA한다. +- 내부 모델명은 아직 `game`을 유지하므로, 다음 단계에서는 문서와 보조 화면 문구를 더 정리할지, 아니면 내부 리네이밍 계획을 따로 잡을지 결정한다. - 게임 목록과 티어표 카드 썸네일은 기본 이미지 드래그를 막았으므로, 데스크톱 브라우저에서 클릭/드래그 시 원본 이미지 프리뷰가 더 이상 뜨지 않는지 한 번 더 QA한다. - 왼쪽 레일 활성 배경은 공용 인디케이터가 이동하는 방식으로 바뀌었으므로, 홈/내 티어표/즐겨찾기/설정 전환과 레일 접힘 상태 양쪽에서 위치 보정이 자연스러운지 한 번 더 QA한다. - 로그인 화면 상단 토글은 이동형 인디케이터로 바뀌었으므로, 데스크톱과 모바일에서 `로그인 / 회원가입` 전환 애니메이션이 어색하지 않고 포커스/클릭 상태도 자연스러운지 한 번 더 QA한다. diff --git a/docs/update.md b/docs/update.md index 412958a..be48a06 100644 --- a/docs/update.md +++ b/docs/update.md @@ -1,5 +1,9 @@ # 업데이트 로그 +## 2026-04-02 v1.4.0 +- 사용자 노출 용어 1차 정리를 시작해 홈/좌측 레일/가이드/주제 화면에서는 `게임` 대신 `주제`, 관리자 핵심 화면에서는 `게임 관리` 대신 `템플릿 관리` 중심 표현으로 바꿨다. +- 내부 데이터 모델과 API의 `gameId`, `/games` 구조는 아직 유지하고, 이번 단계는 화면 문구와 안내 텍스트를 먼저 정리하는 안전한 1차 리네이밍 범위로 제한했다. + ## 2026-04-02 v1.3.93 - 게임 목록, 티어표 리스트, 사용자 아바타 버튼 등 목록성 썸네일 이미지에 `draggable=\"false\"`를 적용해 브라우저 기본 이미지 드래그 프리뷰가 뜨지 않도록 정리함. diff --git a/frontend/src/App.vue b/frontend/src/App.vue index cb13224..8d064fc 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -26,7 +26,7 @@ const RIGHT_RAIL_COPYRIGHT_URL = 'https://zenn.town/@murabito' const leftRailCollapsed = ref(false) const rightRailOpen = ref(true) const searchQuery = ref('') -const leftRailSearchPlaceholder = '게임 템플릿 검색' +const leftRailSearchPlaceholder = '주제 템플릿 검색' const isCollapsedSearchOpen = ref(false) const isGuideModalOpen = ref(false) const themeMode = ref('dark') @@ -60,7 +60,7 @@ const shellStyle = computed(() => ({ })) const leftNavItems = computed(() => { const items = [ - { key: 'home', label: 'Games', path: '/', iconSrc: iconGridView }, + { key: 'home', label: 'Topics', path: '/', iconSrc: iconGridView }, { key: 'me', label: 'My Lists', path: '/me', iconSrc: iconLists, requiresAuth: true }, { key: 'favorites', label: 'Favorites', path: '/favorites', iconSrc: iconFavorite, requiresAuth: true }, { key: 'profile', label: 'Settings', path: '/profile', iconSrc: iconSettings, requiresAuth: true }, @@ -73,10 +73,10 @@ const showSettingsGuideButton = computed(() => route.name === 'profile') const guideSteps = [ { id: 'select-game', - title: '게임 또는 양식 선택', - summary: '게임 템플릿을 고르거나 커스텀 티어표 만들기로 바로 시작합니다.', + title: '주제 또는 양식 선택', + summary: '주제 템플릿을 고르거나 커스텀 티어표 만들기로 바로 시작합니다.', description: - '홈 화면에서는 게임 템플릿을 선택하거나 커스텀 티어표 만들기로 바로 새 보드를 열 수 있어요. 게임을 먼저 고르면 해당 게임의 공개 티어표도 같이 살펴볼 수 있어서, 완전히 처음 만드는지 기존 흐름을 참고할지 결정하기 쉽습니다.', + '홈 화면에서는 주제 템플릿을 선택하거나 커스텀 티어표 만들기로 바로 새 보드를 열 수 있어요. 원하는 주제를 먼저 고르면 해당 주제의 공개 티어표도 같이 살펴볼 수 있어서, 완전히 처음 만드는지 기존 흐름을 참고할지 결정하기 쉽습니다.', }, { id: 'arrange-board', @@ -90,7 +90,7 @@ const guideSteps = [ title: '아이템 배치와 커스텀 추가', summary: '프리셋 아이템과 직접 올린 이미지를 드래그로 배치합니다.', description: - '오른쪽 아이템 영역의 이미지를 원하는 칸으로 끌어다 놓으면 바로 배치됩니다. 게임 템플릿에 없는 이미지는 커스텀 이미지로 추가해 같이 쓸 수 있고, 이름 표시 옵션을 켜면 결과 이미지를 더 설명적으로 정리할 수 있어요.', + '오른쪽 아이템 영역의 이미지를 원하는 칸으로 끌어다 놓으면 바로 배치됩니다. 주제 템플릿에 없는 이미지는 커스텀 이미지로 추가해 같이 쓸 수 있고, 이름 표시 옵션을 켜면 결과 이미지를 더 설명적으로 정리할 수 있어요.', }, { id: 'save-share', @@ -109,23 +109,23 @@ const guideSteps = [ { id: 'request-template-update', title: '템플릿 업그레이드 요청', - summary: '현재 게임 템플릿에 공통 아이템을 추가해 달라고 관리자에게 요청합니다.', + summary: '현재 템플릿에 공통 아이템을 추가해 달라고 관리자에게 요청합니다.', description: '직접 추가한 아이템 중 여러 사람이 함께 써도 좋을 것 같은 항목이 있다면 템플릿 업데이트 요청을 보낼 수 있어요. 요청 모달에서는 현재 티어표 제목과 설명을 기본값으로 가져오고, 필요하면 요청 제목과 설명을 더 다듬어 공통 템플릿에 왜 필요한지 설명할 수 있습니다.', }, { id: 'request-new-template', title: '새 템플릿 추가 요청', - summary: '아직 없는 게임이나 새로운 양식을 관리자에게 제안합니다.', + summary: '아직 없는 주제나 새로운 양식을 관리자에게 제안합니다.', description: - '원하는 게임 템플릿이 아직 없다면 새 템플릿 추가 요청으로 관리자에게 직접 제안할 수 있어요. 이때는 제목과 설명에 어떤 게임인지, 어떤 캐릭터나 항목이 기본으로 필요할지 적어두면 검토 속도가 훨씬 빨라집니다.', + '원하는 주제 템플릿이 아직 없다면 새 템플릿 추가 요청으로 관리자에게 직접 제안할 수 있어요. 이때는 제목과 설명에 어떤 주제인지, 어떤 캐릭터나 항목이 기본으로 필요할지 적어두면 검토 속도가 훨씬 빨라집니다.', }, { id: 'manage-library', title: '즐겨찾기와 내 티어표 관리', summary: '마음에 드는 템플릿과 저장한 결과물을 나중에 다시 쉽게 찾습니다.', description: - '게임 템플릿은 즐겨찾기로 상단에 고정해둘 수 있고, 저장한 보드는 내 티어표에서 다시 열어 이어서 수정할 수 있어요. 자주 보는 템플릿, 공개 티어표, 내가 만든 결과물을 각각 다른 화면에서 정리해두면 이후 작업이 훨씬 빨라집니다.', + '주제 템플릿은 즐겨찾기로 상단에 고정해둘 수 있고, 저장한 보드는 내 티어표에서 다시 열어 이어서 수정할 수 있어요. 자주 보는 템플릿, 공개 티어표, 내가 만든 결과물을 각각 다른 화면에서 정리해두면 이후 작업이 훨씬 빨라집니다.', }, ] const currentGuideStep = computed(() => guideSteps[guideStepIndex.value] || guideSteps[0]) @@ -152,9 +152,9 @@ const routeMeta = computed(() => { if (route.name === 'home') { return { title: 'Tier Maker', - subtitle: '게임 템플릿 선택과 커스텀 보드 시작', + subtitle: '주제 템플릿 선택과 커스텀 보드 시작', contextTitle: '빠른 시작', - contextText: auth.user ? '커스텀 티어표를 만들거나 원하는 게임을 바로 선택할 수 있어요.' : '로그인하면 커스텀 티어표 생성과 개인 목록 관리가 열립니다.', + contextText: auth.user ? '커스텀 티어표를 만들거나 원하는 주제를 바로 선택할 수 있어요.' : '로그인하면 커스텀 티어표 생성과 개인 목록 관리가 열립니다.', actionLabel: auth.user ? '커스텀 티어표 만들기' : '로그인하러 가기', action: () => { router.push(auth.user ? '/editor/freeform/new' : '/login') @@ -163,10 +163,10 @@ const routeMeta = computed(() => { } if (route.name === 'gameHub') { return { - title: 'Game Boards', - subtitle: '게임별 공개 티어표 탐색', + title: 'Topic Boards', + subtitle: '주제별 공개 티어표 탐색', contextTitle: '작성 작업', - contextText: auth.user ? '이 게임의 새 티어표를 만들거나 기존 공개 티어표를 확인할 수 있어요.' : '로그인 후 새 티어표를 만들 수 있어요.', + contextText: auth.user ? '이 주제의 새 티어표를 만들거나 기존 공개 티어표를 확인할 수 있어요.' : '로그인 후 새 티어표를 만들 수 있어요.', actionLabel: auth.user ? '새 티어표 만들기' : '로그인하러 가기', action: () => { const target = `/editor/${route.params.gameId}/new` @@ -180,17 +180,17 @@ const routeMeta = computed(() => { subtitle: '티어표 편집 및 공유', contextTitle: '편집 패널', contextText: '현재 편집 옵션은 중앙 화면 안에 유지되어 있습니다. 다음 단계에서 우측 패널로 정리해갈게요.', - actionLabel: '게임 목록으로', + actionLabel: '주제 목록으로', action: () => router.push('/'), } } if (isAdminRoute.value) { return { title: 'Admin Workspace', - subtitle: '게임·아이템·회원 관리', + subtitle: '템플릿·아이템·회원 관리', contextTitle: '운영 노트', contextText: '관리자 화면은 기능이 많아 우선 공통 셸 톤을 맞췄고, 세부 패널은 다음 단계에서 시안 방식으로 더 세밀하게 나눌 예정입니다.', - actionLabel: '게임 목록으로', + actionLabel: '주제 목록으로', action: () => router.push('/'), } } @@ -236,7 +236,7 @@ const routeMeta = computed(() => { } return { title: 'Tier Maker', - subtitle: '게임 템플릿으로 만드는 티어표', + subtitle: '주제 템플릿으로 만드는 티어표', contextTitle: 'Workspace', contextText: '현재 화면에 맞는 도구와 안내를 여기에 배치할 수 있습니다.', actionLabel: '홈으로', diff --git a/frontend/src/components/admin/AdminFeaturedSection.vue b/frontend/src/components/admin/AdminFeaturedSection.vue index 4008245..28c9626 100644 --- a/frontend/src/components/admin/AdminFeaturedSection.vue +++ b/frontend/src/components/admin/AdminFeaturedSection.vue @@ -16,7 +16,7 @@ const props = defineProps({
홈 화면 상단 고정 순서
-
여기에 넣은 게임은 지정한 순서대로 먼저 노출되고, 나머지 게임은 최근 생성순으로 뒤에 이어집니다. 최대 50개까지 설정할 수 있어요.
+
여기에 넣은 템플릿은 지정한 순서대로 먼저 노출되고, 나머지 템플릿은 최근 생성순으로 뒤에 이어집니다. 최대 50개까지 설정할 수 있어요.
@@ -24,7 +24,7 @@ const props = defineProps({
상단 고정 목록
-
아직 상단 고정 게임이 없어요.
+
아직 상단 고정 템플릿이 없어요.
@@ -45,7 +45,7 @@ const props = defineProps({
-
게임 추가
+
템플릿 추가
- {{ props.activeTemplateRequest.type === 'create' ? '신규 게임 요청' : '기존 게임 업데이트' }} + {{ props.activeTemplateRequest.type === 'create' ? '신규 템플릿 요청' : '기존 템플릿 업데이트' }} 요청 아이템 {{ props.stagedRequestDraftCount }}개 이미 반영 {{ props.appliedRequestItemCount }}개 - 연결된 게임 · {{ props.activeTemplateRequest.targetGameName || props.activeTemplateRequest.targetGameId }} + 연결된 템플릿 · {{ props.activeTemplateRequest.targetGameName || props.activeTemplateRequest.targetGameId }}
@@ -97,15 +97,15 @@ function setThumbFileElement(el) { type="button" @click="props.openGameCreateModal" > - 새 게임 만들기 + 새 템플릿 만들기
-
게임 정보를 불러오는 중이에요.
-
선택한 게임의 썸네일과 기본 아이템을 곧 표시합니다.
+
템플릿 정보를 불러오는 중이에요.
+
선택한 템플릿의 썸네일과 기본 아이템을 곧 표시합니다.
@@ -133,7 +133,7 @@ function setThumbFileElement(el) {
-
게임 설정
+
템플릿 설정
{{ props.selectedGame.game.name }} · {{ props.selectedGame.game.id }}
- +
@@ -236,9 +236,9 @@ function setThumbFileElement(el) {
-
게임을 선택해 주세요.
-
진행 중인 신규 게임 요청이 있어요. 위의 `새 게임 만들기`로 게임을 만든 뒤 아이템을 추가할 수 있습니다.
-
선택한 게임을 찾지 못했거나 로딩 중 오류가 발생했어요. 다시 선택해보세요.
+
템플릿을 선택해 주세요.
+
진행 중인 신규 템플릿 요청이 있어요. 위의 `새 템플릿 만들기`로 템플릿을 만든 뒤 아이템을 추가할 수 있습니다.
+
선택한 템플릿을 찾지 못했거나 로딩 중 오류가 발생했어요. 다시 선택해보세요.
diff --git a/frontend/src/components/admin/AdminTierlistsSection.vue b/frontend/src/components/admin/AdminTierlistsSection.vue index 2aa2330..f308194 100644 --- a/frontend/src/components/admin/AdminTierlistsSection.vue +++ b/frontend/src/components/admin/AdminTierlistsSection.vue @@ -53,18 +53,18 @@ const props = defineProps({
@@ -111,7 +111,7 @@ const props = defineProps({ request.isHandling ? '이동중...' : request.type === 'create' && (request.targetGameName || request.targetGameId) - ? '연결된 게임 열기' + ? '연결된 템플릿 열기' : '확인하기' }} diff --git a/frontend/src/views/AdminView.vue b/frontend/src/views/AdminView.vue index 5e44c61..3cbcd1b 100644 --- a/frontend/src/views/AdminView.vue +++ b/frontend/src/views/AdminView.vue @@ -214,7 +214,7 @@ const customItemTargetGame = computed(() => games.value.find((game) => game.id = const importModalItemCount = computed(() => importModalItems.value.length) const activeTabTitle = computed(() => { if (activeTab.value === 'featured') return '목록 관리' - if (activeTab.value === 'game-admin') return '게임 관리' + if (activeTab.value === 'game-admin') return '템플릿 관리' if (activeTab.value === 'items') return '아이템 관리' if (activeTab.value === 'tierlists') { return tierlistsMode.value === 'requests' ? '템플릿 요청 관리' : '전체 티어표 관리' @@ -223,17 +223,17 @@ const activeTabTitle = computed(() => { }) const activeTabDescription = computed(() => { if (activeTab.value === 'featured') { - return '홈 화면 상단에 고정 노출되는 게임 순서를 따로 관리합니다.' + return '홈 화면 상단에 고정 노출되는 템플릿 순서를 따로 관리합니다.' } if (activeTab.value === 'game-admin') { - return '게임 생성, 선택, 썸네일, 기본 아이템 관리를 전용 작업 화면으로 분리했습니다.' + return '템플릿 생성, 선택, 썸네일, 기본 아이템 관리를 전용 작업 화면으로 분리했습니다.' } if (activeTab.value === 'items') { - return '사용자 업로드와 관리자 템플릿 이미지를 함께 검수하고, 필요한 게임에 직접 연결할 수 있어요.' + return '사용자 업로드와 관리자 템플릿 이미지를 함께 검수하고, 필요한 템플릿에 직접 연결할 수 있어요.' } if (activeTab.value === 'tierlists') { return tierlistsMode.value === 'requests' - ? '사용자 요청을 확인하고, 게임 관리 화면에서 필요한 아이템만 선별 반영한 뒤 직접 완료 처리합니다.' + ? '사용자 요청을 확인하고, 템플릿 관리 화면에서 필요한 아이템만 선별 반영한 뒤 직접 완료 처리합니다.' : '공개/비공개 포함 전체 티어표를 확인하고, 추가 아이템을 템플릿으로 가져올 수 있어요.' } return '계정 정보, 권한, 비밀번호와 최근 활동을 더 가볍게 확인하고 수정합니다.' @@ -245,14 +245,14 @@ const adminOverviewStats = computed(() => { if (activeTab.value === 'featured') { return [ - { label: '전체 게임', value: `${games.value.length}` }, + { label: '전체 템플릿', value: `${games.value.length}` }, { label: '상단 고정', value: `${featuredGameIds.value.length}/50` }, { label: '추가 가능', value: `${Math.max(0, 50 - featuredGameIds.value.length)}` }, ] } if (activeTab.value === 'game-admin') { return [ - { label: '전체 게임', value: `${games.value.length}` }, + { label: '전체 템플릿', value: `${games.value.length}` }, { label: '티어표 전체', value: `${selectedGameTierListStats.value.total || 0}` }, { label: '공개', value: `${selectedGameTierListStats.value.publicCount || 0}` }, { label: '비공개', value: `${selectedGameTierListStats.value.privateCount || 0}` }, @@ -794,7 +794,7 @@ async function refreshGames() { .map((game) => game.id) await syncFeaturedSortable() } catch (e) { - error.value = '게임 목록을 불러오지 못했어요.' + error.value = '템플릿 목록을 불러오지 못했어요.' } } @@ -1275,7 +1275,7 @@ async function removeGame() { await refreshGames() success.value = `${deletedName} 게임을 삭제했어요.` } catch (e) { - error.value = '게임 삭제에 실패했어요.' + error.value = '템플릿 삭제에 실패했어요.' } } @@ -1570,7 +1570,7 @@ async function confirmTierListImport() { try { if (importModalMode.value === 'existing') { if (!importModalTargetGameId.value) { - error.value = '아이템을 추가할 기존 게임을 선택해주세요.' + error.value = '아이템을 추가할 기존 템플릿을 선택해주세요.' return } @@ -1584,7 +1584,7 @@ async function confirmTierListImport() { const nextGameId = (importModalNewGameId.value || '').trim() const nextGameName = (importModalNewGameName.value || '').trim() if (!nextGameId || !nextGameName) { - error.value = '새 게임 ID와 이름을 모두 입력해주세요.' + error.value = '새 템플릿 ID와 이름을 모두 입력해주세요.' return } @@ -1610,9 +1610,9 @@ function templateRequestTypeLabel(request) { function templateRequestTargetLabel(request) { if (request.type === 'create') { if (request.targetGameName || request.targetGameId) { - return `연결된 게임 · ${request.targetGameName || request.targetGameId}` + return `연결된 템플릿 · ${request.targetGameName || request.targetGameId}` } - return '연결된 게임 없음' + return '연결된 템플릿 없음' } return request.targetGameName || request.targetGameId || request.sourceGameName } @@ -1787,16 +1787,16 @@ function userAvatarFallback(user) {
@@ -1925,14 +1925,14 @@ function userAvatarFallback(user) {
- - + +
@@ -1953,12 +1953,12 @@ function userAvatarFallback(user) {
템플릿으로 추가할 게임
-
선택한 게임
+
선택한 템플릿
{{ customItemTargetGame?.name || '아직 선택하지 않음' }}
{{ customItemTargetGame?.id || '게임을 골라 주세요.' }}
- +
@@ -1991,7 +1991,7 @@ function userAvatarFallback(user) {
-
아직 템플릿에 연결된 게임이 없어요.
+
아직 템플릿에 연결된 항목이 없어요.
이미지 다운로드 @@ -2010,7 +2010,7 @@ function userAvatarFallback(user) {