- 대시보드(/admin/dashboard, 기본 랜딩): 요약 카드(총회원·금일 신규/탈퇴·DAU/WAU/MAU), 접속자 추이(일/주/월 토글), 티어별 회원수, 시군구 지역 분포 — 모두 체크인 기반 - 회원 상세(/admin/members/:id): 프로필 + 강아지/체크인/매칭/구독 이력, 목록에서 상세 버튼 - adminStats API 모듈, 좌측 메뉴에 대시보드 추가 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -5,10 +5,49 @@ 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<Member[]>('/api/admin/members'),
|
||||
|
||||
detail: (id: number) => http.get<MemberDetail>(`/api/admin/members/${id}`),
|
||||
|
||||
updateStatus: (id: number, status: MemberStatus) =>
|
||||
http.put<Member>(`/api/admin/members/${id}/status`, { status }),
|
||||
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
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<StatsSummary>('/api/admin/stats/summary'),
|
||||
visitors: (unit: VisitorUnit) => http.get<VisitorPoint[]>(`/api/admin/stats/visitors?unit=${unit}`),
|
||||
regions: () => http.get<RegionStat[]>('/api/admin/stats/regions'),
|
||||
}
|
||||
Reference in New Issue
Block a user