diff --git a/package-lock.json b/package-lock.json index d183fa8..00d8c4d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -925,9 +925,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -949,9 +946,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -973,9 +967,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -997,9 +988,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1021,9 +1009,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1045,9 +1030,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1246,9 +1228,6 @@ "arm" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1263,9 +1242,6 @@ "arm" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1280,9 +1256,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1297,9 +1270,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1314,9 +1284,6 @@ "loong64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1331,9 +1298,6 @@ "loong64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1348,9 +1312,6 @@ "ppc64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1365,9 +1326,6 @@ "ppc64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1382,9 +1340,6 @@ "riscv64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1399,9 +1354,6 @@ "riscv64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -1416,9 +1368,6 @@ "s390x" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1433,9 +1382,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -1450,9 +1396,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -3036,7 +2979,6 @@ "arm" ], "dev": true, - "libc": "glibc", "license": "MIT", "optional": true, "os": [ @@ -3054,7 +2996,6 @@ "arm64" ], "dev": true, - "libc": "glibc", "license": "MIT", "optional": true, "os": [ @@ -3072,7 +3013,6 @@ "arm" ], "dev": true, - "libc": "musl", "license": "MIT", "optional": true, "os": [ @@ -3090,7 +3030,6 @@ "arm64" ], "dev": true, - "libc": "musl", "license": "MIT", "optional": true, "os": [ @@ -3108,7 +3047,6 @@ "riscv64" ], "dev": true, - "libc": "musl", "license": "MIT", "optional": true, "os": [ @@ -3126,7 +3064,6 @@ "x64" ], "dev": true, - "libc": "musl", "license": "MIT", "optional": true, "os": [ @@ -3144,7 +3081,6 @@ "riscv64" ], "dev": true, - "libc": "glibc", "license": "MIT", "optional": true, "os": [ @@ -3162,7 +3098,6 @@ "x64" ], "dev": true, - "libc": "glibc", "license": "MIT", "optional": true, "os": [ diff --git a/src/api/adminAuth.ts b/src/api/adminAuth.ts deleted file mode 100644 index 0d5b880..0000000 --- a/src/api/adminAuth.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { http } from './http' -import type { LoginResponse } from './auth' - -/** 관리자 콘솔 전용 인증 API (사용자 authApi 와 분리). */ -export const adminAuthApi = { - /** 개발자 로그인 — local 백엔드 전용(구글 없이 이메일로 세션 발급). */ - devLogin: (email: string) => http.post('/api/auth/dev-login', { email }), -} diff --git a/src/api/adminMembers.ts b/src/api/adminMembers.ts deleted file mode 100644 index 9a57f93..0000000 --- a/src/api/adminMembers.ts +++ /dev/null @@ -1,61 +0,0 @@ -import { http } from './http' -import type { Member } from './auth' - -export type MemberStatus = 'ACTIVE' | 'DORMANT' | 'BANNED' -export type MemberTier = 'FREE' | 'AD_FREE' | 'PREMIUM' -export type MemberRole = 'USER' | 'ADMIN' - -export interface DogDetail { - id: number - name: string - breed: string | null - size: string | null - gender: string | null - neutered: boolean - birthDate: string | null - imageUrl: string | null -} -export interface CheckInDetail { - spotName: string - region: string | null - checkedInAt: string -} -export interface MatchDetail { - id: number - direction: string - counterpartDog: string - status: string - createdAt: string -} -export interface SubscriptionDetail { - tier: string - platform: string - startedAt: string - expiresAt: string - active: boolean -} -export interface MemberDetail { - member: Member - dogs: DogDetail[] - checkIns: CheckInDetail[] - matches: MatchDetail[] - subscriptions: SubscriptionDetail[] -} - -/** 관리자 회원관리 API — /api/admin/members (ADMIN 전용) */ -export const adminMembersApi = { - list: () => http.get('/api/admin/members'), - - detail: (id: number) => http.get(`/api/admin/members/${id}`), - - updateStatus: (id: number, status: MemberStatus) => - http.put(`/api/admin/members/${id}/status`, { status }), - - updateTier: (id: number, tier: MemberTier) => - http.put(`/api/admin/members/${id}/tier`, { tier }), - - updateRole: (id: number, role: MemberRole) => - http.put(`/api/admin/members/${id}/role`, { role }), - - remove: (id: number) => http.del(`/api/admin/members/${id}`), -} diff --git a/src/api/adminStats.ts b/src/api/adminStats.ts deleted file mode 100644 index da43b01..0000000 --- a/src/api/adminStats.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { http } from './http' - -export interface Count { - key: string - count: number -} - -export interface StatsSummary { - members: { total: number; byTier: Count[]; byStatus: Count[] } - today: { signups: number; withdrawals: number } - visitors: { dau: number; wau: number; mau: number } -} - -export interface VisitorPoint { - label: string - count: number -} - -export interface RegionStat { - region: string - checkIns: number - users: number -} - -export type VisitorUnit = 'day' | 'week' | 'month' - -/** 관리자 대시보드 통계 API (체크인 기반) */ -export const adminStatsApi = { - summary: () => http.get('/api/admin/stats/summary'), - visitors: (unit: VisitorUnit) => http.get(`/api/admin/stats/visitors?unit=${unit}`), - regions: () => http.get('/api/admin/stats/regions'), -} diff --git a/src/layouts/AdminLayout.vue b/src/layouts/AdminLayout.vue deleted file mode 100644 index c30072e..0000000 --- a/src/layouts/AdminLayout.vue +++ /dev/null @@ -1,70 +0,0 @@ - - - diff --git a/src/pages/admin/AdminDashboardPage.vue b/src/pages/admin/AdminDashboardPage.vue deleted file mode 100644 index 10164fe..0000000 --- a/src/pages/admin/AdminDashboardPage.vue +++ /dev/null @@ -1,253 +0,0 @@ - - - - - diff --git a/src/pages/admin/AdminLoginPage.vue b/src/pages/admin/AdminLoginPage.vue deleted file mode 100644 index d19a833..0000000 --- a/src/pages/admin/AdminLoginPage.vue +++ /dev/null @@ -1,143 +0,0 @@ - - - - - diff --git a/src/pages/admin/AdminMemberDetailPage.vue b/src/pages/admin/AdminMemberDetailPage.vue deleted file mode 100644 index 04eff28..0000000 --- a/src/pages/admin/AdminMemberDetailPage.vue +++ /dev/null @@ -1,203 +0,0 @@ - - - diff --git a/src/pages/admin/AdminMembersPage.vue b/src/pages/admin/AdminMembersPage.vue deleted file mode 100644 index 8c5ceda..0000000 --- a/src/pages/admin/AdminMembersPage.vue +++ /dev/null @@ -1,260 +0,0 @@ - - - diff --git a/src/router/index.ts b/src/router/index.ts index e77156b..0ebd452 100644 --- a/src/router/index.ts +++ b/src/router/index.ts @@ -1,7 +1,6 @@ import { createRouter, createWebHistory, type RouteRecordRaw } from 'vue-router' import MainLayout from '@/layouts/MainLayout.vue' import { useAuthStore } from '@/stores/auth' -import { useAdminAuthStore } from '@/stores/adminAuth' const routes: RouteRecordRaw[] = [ { @@ -18,35 +17,6 @@ const routes: RouteRecordRaw[] = [ { path: 'profile', name: 'profile', component: () => import('@/pages/ProfilePage.vue') }, ], }, - // 관리자 콘솔 (웹 전용) — 사용자 앱과 분리 - { - path: '/admin/login', - name: 'admin-login', - component: () => import('@/pages/admin/AdminLoginPage.vue'), - }, - { - path: '/admin', - component: () => import('@/layouts/AdminLayout.vue'), - meta: { requiresAdmin: true }, - children: [ - { path: '', redirect: { name: 'admin-dashboard' } }, - { - path: 'dashboard', - name: 'admin-dashboard', - component: () => import('@/pages/admin/AdminDashboardPage.vue'), - }, - { - path: 'members', - name: 'admin-members', - component: () => import('@/pages/admin/AdminMembersPage.vue'), - }, - { - path: 'members/:id', - name: 'admin-member-detail', - component: () => import('@/pages/admin/AdminMemberDetailPage.vue'), - }, - ], - }, ] const router = createRouter({ @@ -56,10 +26,6 @@ const router = createRouter({ // 소셜 로그인 전용 앱: 미로그인 시 보호 경로 접근 → 로그인으로 router.beforeEach((to) => { - // 관리자 경로는 아래 관리자 가드가 처리 (사용자 가드는 관여하지 않음) - if (to.matched.some((r) => r.meta.requiresAdmin) || to.name === 'admin-login') { - return true - } const auth = useAuthStore() if (to.meta.requiresAuth && !auth.isAuthenticated) { return { name: 'login', query: { redirect: to.fullPath } } @@ -69,22 +35,4 @@ router.beforeEach((to) => { } }) -// 관리자 콘솔 가드 — 토큰/회원 복원 후 ADMIN 여부 확인 (사용자 인증과 분리) -router.beforeEach(async (to) => { - const needsAdmin = to.matched.some((r) => r.meta.requiresAdmin) - if (!needsAdmin && to.name !== 'admin-login') return true - - const admin = useAdminAuthStore() - if (admin.hasToken() && !admin.member) { - await admin.fetchMe() - } - if (needsAdmin && !admin.isAdmin) { - return { name: 'admin-login' } - } - if (to.name === 'admin-login' && admin.isAdmin) { - return { name: 'admin-dashboard' } - } - return true -}) - export default router diff --git a/src/stores/adminAuth.ts b/src/stores/adminAuth.ts deleted file mode 100644 index bfe8f57..0000000 --- a/src/stores/adminAuth.ts +++ /dev/null @@ -1,62 +0,0 @@ -import { defineStore } from 'pinia' -import { computed, ref } from 'vue' -import { authApi, type Member } from '@/api/auth' -import { adminAuthApi } from '@/api/adminAuth' -import { tokenStore } from '@/lib/token' - -/** - * 관리자 콘솔 전용 인증 스토어 (사용자 auth 스토어와 분리). - * 저수준 토큰 저장소(tokenStore)와 소셜 로그인/조회(authApi)는 공용을 재사용한다. - */ -export const useAdminAuthStore = defineStore('adminAuth', () => { - const member = ref(null) - const isAdmin = computed(() => member.value?.role === 'ADMIN') - - function hasToken(): boolean { - return !!tokenStore.get() - } - - /** 구글 로그인 → 토큰 저장 + 회원 세팅. */ - async function loginWithGoogle(idToken: string): Promise { - const res = await authApi.google(idToken) - tokenStore.set(res.token) - member.value = res.member - return res.member - } - - /** 개발자 로그인 (local 백엔드 전용). */ - async function loginDev(email: string): Promise { - const res = await adminAuthApi.devLogin(email) - tokenStore.set(res.token) - member.value = res.member - return res.member - } - - /** 토큰으로 회원 복원(새로고침/가드). 실패 시 세션 정리. */ - async function fetchMe(): Promise { - if (!tokenStore.get()) return null - try { - member.value = await authApi.me() - return member.value - } catch { - clear() - return null - } - } - - async function logout(): Promise { - try { - await authApi.logout() - } catch { - /* 서버 실패해도 로컬 세션은 정리 */ - } - clear() - } - - function clear(): void { - tokenStore.clear() - member.value = null - } - - return { member, isAdmin, hasToken, loginWithGoogle, loginDev, fetchMe, logout, clear } -})