릴리스: v1.4.11 프런트 API 명칭 정리 1차
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
# 의사결정 이력
|
||||
|
||||
## 2026-04-02 v1.4.11
|
||||
- 백엔드 `/api/games` 경로를 바로 바꾸기보다, 프런트 API 객체에서 먼저 `topic/template` 의미 이름을 제공하고 호출부를 옮기는 편이 위험이 훨씬 낮다고 판단했다.
|
||||
|
||||
## 2026-04-02 v1.4.10
|
||||
- 사용자 주소는 이미 `/topics`로 옮기기 시작했으므로, 라우트 이름과 기본 파라미터도 `topicHub / topicId` 기준으로 맞추고 기존 `gameId`는 호환 fallback으로만 남기는 편이 더 자연스럽다고 판단했다.
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# 할 일 및 이슈
|
||||
|
||||
## 단기 확인
|
||||
- 프런트 API 호출부는 `topic/template` 의미 이름으로 옮겼으므로, 다음 단계에서는 `api.js` 안의 레거시 alias를 얼마나 더 유지할지와 백엔드 API 경로를 실제로 바꿀지 범위를 정한다.
|
||||
- 관리자 템플릿/주제 화면과 홈·에디터·즐겨찾기에서 새 API 이름층으로 바뀐 뒤에도 저장, 즐겨찾기, 템플릿 생성, 아이템 정렬 흐름이 자연스러운지 한 번 더 QA한다.
|
||||
- `topicHub / topicId`를 기본 라우트 기준으로 세웠으므로, 기존 `/games/...` 북마크와 새 `/topics/...` 주소 양쪽에서 주제 상세와 에디터 진입이 모두 자연스럽게 이어지는지 한 번 더 QA한다.
|
||||
- 다음 단계에서는 `api.getGame`, `listGames`, `favoriteGame`처럼 남아 있는 프런트 API 이름을 어느 수준까지 `topic/template` 의미로 감쌀지 정리한다.
|
||||
- 경로 헬퍼를 사용자 주요 화면에 연결했으므로, 로그인 리다이렉트·공유 프리뷰·복사본 이동·주제 복귀 흐름이 실제 브라우저에서 모두 같은 주소 체계로 자연스럽게 이어지는지 한 번 더 QA한다.
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
# 업데이트 로그
|
||||
|
||||
## 2026-04-02 v1.4.11
|
||||
- 프런트 API 이름층을 한 단계 더 정리해 `listTopics / getTopic / favoriteTopic`, `updateAdminTemplate*`, `searchPublicTierListsByTopic` 같은 의미 기반 이름을 추가하고 실제 호출부도 이 기준으로 옮겼다.
|
||||
- 백엔드 경로와 응답 구조는 그대로 유지한 채 프런트에서 읽는 이름만 먼저 바꿔, 다음 단계의 API/모델 리네이밍 부담을 더 줄였다.
|
||||
|
||||
## 2026-04-02 v1.4.10
|
||||
- 주제 상세 라우트 이름을 `topicHub`로, 기본 경로 파라미터를 `topicId`로 바꾸고 기존 `gameId` 주소는 alias로 유지했다.
|
||||
- 앱 셸, 주제 상세, 티어표 편집기는 이제 내부에서 `topicId`를 우선 읽고, 레거시 주소로 들어온 경우에만 `gameId` fallback을 쓰도록 정리했다.
|
||||
|
||||
@@ -167,7 +167,7 @@ export function useAdminCustomItems({
|
||||
|
||||
try {
|
||||
item.isPromoting = true
|
||||
await api.promoteAdminCustomItem(item.id, { gameId: customItemModalTargetTemplateId.value })
|
||||
await api.promoteAdminTemplateItem(item.id, { gameId: customItemModalTargetTemplateId.value })
|
||||
const targetTemplateName =
|
||||
templates.value.find((template) => template.id === customItemModalTargetTemplateId.value)?.name || customItemModalTargetTemplateId.value
|
||||
if (selectedTemplateId.value === customItemModalTargetTemplateId.value) await loadTemplate()
|
||||
|
||||
@@ -70,7 +70,7 @@ export function useAdminFeaturedGames({
|
||||
async function saveFeaturedOrder() {
|
||||
resetMessages()
|
||||
try {
|
||||
const data = await api.updateAdminGameDisplayOrder({ gameIds: featuredTemplateIds.value })
|
||||
const data = await api.updateAdminTemplateDisplayOrder({ gameIds: featuredTemplateIds.value })
|
||||
templates.value = data.games || []
|
||||
featuredTemplateIds.value = templates.value
|
||||
.filter((template) => template.displayRank != null)
|
||||
|
||||
@@ -131,7 +131,7 @@ export function useAdminGameManager({
|
||||
|
||||
try {
|
||||
isGameLoading.value = true
|
||||
const data = await api.getGame(selectedTemplateId.value)
|
||||
const data = await api.getTopic(selectedTemplateId.value)
|
||||
selectedTemplate.value = {
|
||||
...data,
|
||||
items: (data.items || []).map((item) => ({
|
||||
@@ -336,7 +336,7 @@ export function useAdminGameManager({
|
||||
if (!selectedTemplateId.value || !selectedTemplate.value?.items?.length) return
|
||||
|
||||
try {
|
||||
const data = await api.updateAdminGameItemDisplayOrder(selectedTemplateId.value, {
|
||||
const data = await api.updateAdminTemplateItemDisplayOrder(selectedTemplateId.value, {
|
||||
itemIds: selectedTemplate.value.items.map((item) => item.id),
|
||||
})
|
||||
selectedTemplate.value = {
|
||||
|
||||
@@ -30,17 +30,17 @@ export const api = {
|
||||
login: ({ email, password }) => request('/api/auth/login', { method: 'POST', body: { email, password } }),
|
||||
logout: () => request('/api/auth/logout', { method: 'POST' }),
|
||||
|
||||
listGames: () => request('/api/games'),
|
||||
getGame: (gameId) => request(`/api/games/${encodeURIComponent(gameId)}`),
|
||||
favoriteGame: (gameId) => request(`/api/games/${encodeURIComponent(gameId)}/favorite`, { method: 'POST' }),
|
||||
unfavoriteGame: (gameId) => request(`/api/games/${encodeURIComponent(gameId)}/favorite`, { method: 'DELETE' }),
|
||||
updateAdminGameDisplayOrder: (payload) => request('/api/admin/games/display-order', { method: 'PATCH', body: payload }),
|
||||
updateAdminGameItemDisplayOrder: (gameId, payload) =>
|
||||
request(`/api/admin/games/${encodeURIComponent(gameId)}/items/display-order`, { method: 'PATCH', body: payload }),
|
||||
updateAdminGame: (gameId, payload) =>
|
||||
request(`/api/admin/games/${encodeURIComponent(gameId)}`, { method: 'PATCH', body: payload }),
|
||||
updateAdminGameItem: (gameId, itemId, payload) =>
|
||||
request(`/api/admin/games/${encodeURIComponent(gameId)}/items/${encodeURIComponent(itemId)}`, { method: 'PATCH', body: payload }),
|
||||
listTopics: () => request('/api/games'),
|
||||
getTopic: (topicId) => request(`/api/games/${encodeURIComponent(topicId)}`),
|
||||
favoriteTopic: (topicId) => request(`/api/games/${encodeURIComponent(topicId)}/favorite`, { method: 'POST' }),
|
||||
unfavoriteTopic: (topicId) => request(`/api/games/${encodeURIComponent(topicId)}/favorite`, { method: 'DELETE' }),
|
||||
updateAdminTemplateDisplayOrder: (payload) => request('/api/admin/games/display-order', { method: 'PATCH', body: payload }),
|
||||
updateAdminTemplateItemDisplayOrder: (templateId, payload) =>
|
||||
request(`/api/admin/games/${encodeURIComponent(templateId)}/items/display-order`, { method: 'PATCH', body: payload }),
|
||||
updateAdminTemplate: (templateId, payload) =>
|
||||
request(`/api/admin/games/${encodeURIComponent(templateId)}`, { method: 'PATCH', body: payload }),
|
||||
updateAdminTemplateItem: (templateId, itemId, payload) =>
|
||||
request(`/api/admin/games/${encodeURIComponent(templateId)}/items/${encodeURIComponent(itemId)}`, { method: 'PATCH', body: payload }),
|
||||
listAdminCustomItems: ({ q = '', page = 1, limit = 50, filter = 'all' } = {}) =>
|
||||
request(
|
||||
`/api/admin/custom-items?q=${encodeURIComponent(q)}&page=${encodeURIComponent(page)}&limit=${encodeURIComponent(limit)}&filter=${encodeURIComponent(filter)}`
|
||||
@@ -66,13 +66,13 @@ export const api = {
|
||||
cleanupAdminMissingImageReferences: () => request('/api/admin/image-assets/missing/cleanup', { method: 'POST', body: {} }),
|
||||
listAdminUnusedImageAssets: ({ limit = 100, minAgeHours = 24 } = {}) => request(`/api/admin/image-assets/orphans?limit=${encodeURIComponent(limit)}&minAgeHours=${encodeURIComponent(minAgeHours)}`),
|
||||
cleanupAdminUnusedImageAssets: (payload) => request('/api/admin/image-assets/cleanup', { method: 'POST', body: payload || {} }),
|
||||
promoteAdminCustomItem: (itemId, payload) =>
|
||||
promoteAdminTemplateItem: (itemId, payload) =>
|
||||
request(`/api/admin/custom-items/${encodeURIComponent(itemId)}/promote`, { method: 'POST', body: payload }),
|
||||
updateAdminCustomItemLabel: (itemId, payload) =>
|
||||
request(`/api/admin/custom-items/${encodeURIComponent(itemId)}/label`, { method: 'PATCH', body: payload }),
|
||||
promoteAdminTierListItems: (tierListId, payload) =>
|
||||
request(`/api/admin/tierlists/${encodeURIComponent(tierListId)}/promote-items`, { method: 'POST', body: payload }),
|
||||
createAdminGameTemplateFromTierList: (tierListId, payload) =>
|
||||
createAdminTemplateFromTierList: (tierListId, payload) =>
|
||||
request(`/api/admin/tierlists/${encodeURIComponent(tierListId)}/create-game-template`, { method: 'POST', body: payload }),
|
||||
startAdminTemplateRequestReview: (requestId) =>
|
||||
request(`/api/admin/template-requests/${encodeURIComponent(requestId)}/review`, { method: 'POST', body: {} }),
|
||||
@@ -111,10 +111,10 @@ export const api = {
|
||||
},
|
||||
deleteAdminUser: (userId) => request(`/api/admin/users/${encodeURIComponent(userId)}`, { method: 'DELETE' }),
|
||||
|
||||
listPublicTierLists: (gameId) =>
|
||||
request(`/api/tierlists/public?gameId=${encodeURIComponent(gameId || '')}`),
|
||||
searchPublicTierLists: (gameId, q = '') =>
|
||||
request(`/api/tierlists/public?gameId=${encodeURIComponent(gameId || '')}&q=${encodeURIComponent(q || '')}`),
|
||||
listPublicTierListsByTopic: (topicId) =>
|
||||
request(`/api/tierlists/public?gameId=${encodeURIComponent(topicId || '')}`),
|
||||
searchPublicTierListsByTopic: (topicId, q = '') =>
|
||||
request(`/api/tierlists/public?gameId=${encodeURIComponent(topicId || '')}&q=${encodeURIComponent(q || '')}`),
|
||||
searchAllPublicTierLists: (q = '') => request(`/api/tierlists/public?q=${encodeURIComponent(q || '')}`),
|
||||
listMyTierLists: () => request('/api/tierlists/me'),
|
||||
listMyFavoriteTierLists: ({ q = '', sort = 'favorited' } = {}) =>
|
||||
@@ -146,4 +146,24 @@ export const api = {
|
||||
deleteAdminCustomItem: (itemId) => request(`/api/admin/custom-items/${encodeURIComponent(itemId)}`, { method: 'DELETE' }),
|
||||
deleteAdminUnusedCustomItems: ({ q = '' } = {}) =>
|
||||
request(`/api/admin/custom-items?q=${encodeURIComponent(q)}`, { method: 'DELETE' }),
|
||||
|
||||
listGames: () => request('/api/games'),
|
||||
getGame: (gameId) => request(`/api/games/${encodeURIComponent(gameId)}`),
|
||||
favoriteGame: (gameId) => request(`/api/games/${encodeURIComponent(gameId)}/favorite`, { method: 'POST' }),
|
||||
unfavoriteGame: (gameId) => request(`/api/games/${encodeURIComponent(gameId)}/favorite`, { method: 'DELETE' }),
|
||||
updateAdminGameDisplayOrder: (payload) => request('/api/admin/games/display-order', { method: 'PATCH', body: payload }),
|
||||
updateAdminGameItemDisplayOrder: (gameId, payload) =>
|
||||
request(`/api/admin/games/${encodeURIComponent(gameId)}/items/display-order`, { method: 'PATCH', body: payload }),
|
||||
updateAdminGame: (gameId, payload) =>
|
||||
request(`/api/admin/games/${encodeURIComponent(gameId)}`, { method: 'PATCH', body: payload }),
|
||||
updateAdminGameItem: (gameId, itemId, payload) =>
|
||||
request(`/api/admin/games/${encodeURIComponent(gameId)}/items/${encodeURIComponent(itemId)}`, { method: 'PATCH', body: payload }),
|
||||
promoteAdminCustomItem: (itemId, payload) =>
|
||||
request(`/api/admin/custom-items/${encodeURIComponent(itemId)}/promote`, { method: 'POST', body: payload }),
|
||||
createAdminGameTemplateFromTierList: (tierListId, payload) =>
|
||||
request(`/api/admin/tierlists/${encodeURIComponent(tierListId)}/create-game-template`, { method: 'POST', body: payload }),
|
||||
listPublicTierLists: (gameId) =>
|
||||
request(`/api/tierlists/public?gameId=${encodeURIComponent(gameId || '')}`),
|
||||
searchPublicTierLists: (gameId, q = '') =>
|
||||
request(`/api/tierlists/public?gameId=${encodeURIComponent(gameId || '')}&q=${encodeURIComponent(q || '')}`),
|
||||
}
|
||||
|
||||
@@ -787,7 +787,7 @@ async function selectAdminTemplate(templateId) {
|
||||
|
||||
async function refreshTemplates() {
|
||||
try {
|
||||
const data = await api.listGames()
|
||||
const data = await api.listTopics()
|
||||
templates.value = data.games || []
|
||||
featuredTemplateIds.value = templates.value
|
||||
.filter((template) => template.displayRank != null)
|
||||
@@ -1170,7 +1170,7 @@ async function saveTemplateVisibility() {
|
||||
if (!selectedTemplate.value?.game?.id) return
|
||||
try {
|
||||
gameVisibilitySaving.value = true
|
||||
const data = await api.updateAdminGame(selectedTemplate.value.game.id, {
|
||||
const data = await api.updateAdminTemplate(selectedTemplate.value.game.id, {
|
||||
isPublic: !!selectedTemplate.value.game.isPublic,
|
||||
})
|
||||
selectedTemplate.value = {
|
||||
@@ -1244,7 +1244,7 @@ async function saveTemplateItemLabel(item) {
|
||||
|
||||
try {
|
||||
item.isSavingLabel = true
|
||||
const data = await api.updateAdminGameItem(selectedTemplateId.value, item.id, { label: nextLabel })
|
||||
const data = await api.updateAdminTemplateItem(selectedTemplateId.value, item.id, { label: nextLabel })
|
||||
item.label = data.item.label
|
||||
item.draftLabel = data.item.label
|
||||
success.value = '기본 아이템 이름을 수정했어요.'
|
||||
@@ -1589,7 +1589,7 @@ async function confirmTierListImport() {
|
||||
return
|
||||
}
|
||||
|
||||
const data = await api.createAdminGameTemplateFromTierList(tierList.id, {
|
||||
const data = await api.createAdminTemplateFromTierList(tierList.id, {
|
||||
gameId: nextGameId,
|
||||
name: nextGameName,
|
||||
itemIds,
|
||||
|
||||
@@ -54,8 +54,8 @@ async function loadTierLists() {
|
||||
isTopicLoading.value = true
|
||||
try {
|
||||
const [gameRes, listRes] = await Promise.all([
|
||||
api.getGame(topicId.value),
|
||||
api.searchPublicTierLists(topicId.value, query.value),
|
||||
api.getTopic(topicId.value),
|
||||
api.searchPublicTierListsByTopic(topicId.value, query.value),
|
||||
])
|
||||
topicName.value = gameRes.game?.name || ''
|
||||
brokenThumbnailIds.value = {}
|
||||
|
||||
@@ -36,7 +36,7 @@ const templates = computed(() => {
|
||||
|
||||
async function loadTemplates() {
|
||||
try {
|
||||
const data = await api.listGames()
|
||||
const data = await api.listTopics()
|
||||
templateRecords.value = data.games || []
|
||||
} catch (e) {
|
||||
error.value = '백엔드에 연결할 수 없어요. backend 서버가 실행 중인지 확인해주세요.'
|
||||
@@ -60,7 +60,7 @@ async function toggleFavorite(template, event) {
|
||||
|
||||
try {
|
||||
loadingFavoriteId.value = template.id
|
||||
const res = template.isFavorited ? await api.unfavoriteGame(template.id) : await api.favoriteGame(template.id)
|
||||
const res = template.isFavorited ? await api.unfavoriteTopic(template.id) : await api.favoriteTopic(template.id)
|
||||
templateRecords.value = templateRecords.value.map((entry) => (entry.id === template.id ? { ...entry, ...res.game } : entry))
|
||||
} catch (e) {
|
||||
error.value = '즐겨찾기 변경에 실패했어요.'
|
||||
|
||||
@@ -898,7 +898,7 @@ onMounted(() => {
|
||||
}
|
||||
|
||||
try {
|
||||
const gameRes = await api.getGame(templateId.value)
|
||||
const gameRes = await api.getTopic(templateId.value)
|
||||
templateName.value = gameRes.game?.name || templateId.value
|
||||
const base = (gameRes.items || []).map((img) => ({
|
||||
id: img.id,
|
||||
|
||||
Reference in New Issue
Block a user