feat: add admin dashboard backend and deployment workflow
All checks were successful
Deploy Blog Backend / test (push) Successful in 2m41s
Deploy Blog Backend / deploy (push) Successful in 1m29s

This commit is contained in:
wypark
2026-05-28 21:44:05 +09:00
parent 4c1bd8197f
commit c14d123fcc
25 changed files with 2271 additions and 11 deletions

View File

@@ -0,0 +1,26 @@
package me.wypark.blogbackend.api.controller.admin
import me.wypark.blogbackend.api.common.ApiResponse
import me.wypark.blogbackend.api.dto.AdminDashboardResponse
import me.wypark.blogbackend.domain.dashboard.AdminDashboardService
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
@RestController
@RequestMapping("/api/admin/dashboard")
class AdminDashboardController(
private val adminDashboardService: AdminDashboardService
) {
@GetMapping
fun getDashboard(
@RequestParam(required = false) range: String?,
@RequestParam(required = false) timezone: String?
): ResponseEntity<ApiResponse<AdminDashboardResponse>> {
val dashboard = adminDashboardService.getDashboard(range, timezone)
return ResponseEntity.ok(ApiResponse.success(dashboard, "OK"))
}
}

View File

@@ -0,0 +1,89 @@
package me.wypark.blogbackend.api.dto
import java.math.BigDecimal
import java.time.LocalDate
import java.time.OffsetDateTime
data class DashboardMetric(
val value: Long,
val previousValue: Long? = null,
val changeRate: BigDecimal? = null
)
data class DashboardOverview(
val todayViews: DashboardMetric,
val weekViews: DashboardMetric,
val monthViews: DashboardMetric,
val totalPosts: Long,
val totalComments: Long,
val totalCategories: Long,
val lastPublishedAt: OffsetDateTime?,
val generatedAt: OffsetDateTime
)
data class DashboardTrafficPoint(
val date: LocalDate,
val views: Long
)
data class DashboardPostStat(
val id: Long,
val title: String,
val slug: String,
val categoryName: String,
val viewCount: Long,
val rangeViewCount: Long,
val commentCount: Long,
val createdAt: OffsetDateTime,
val updatedAt: OffsetDateTime?
)
data class DashboardCategoryStat(
val id: Long,
val name: String,
val parentId: Long?,
val postCount: Long,
val viewCount: Long,
val recentViewCount: Long,
val lastPublishedAt: OffsetDateTime?,
val childrenCount: Long
)
data class DashboardActionItems(
val unansweredComments: Long,
val uncategorizedPosts: Long,
val stalePopularPosts: Long
)
data class DashboardPostSummary(
val id: Long,
val title: String,
val slug: String,
val categoryName: String,
val viewCount: Long,
val createdAt: OffsetDateTime,
val tags: List<String>
)
data class AdminDashboardCommentSummary(
val id: Long,
val content: String,
val author: String?,
val guestNickname: String?,
val memberNickname: String?,
val postSlug: String?,
val postTitle: String?,
val createdAt: OffsetDateTime
)
data class AdminDashboardResponse(
val overview: DashboardOverview,
val traffic: List<DashboardTrafficPoint>,
val topPosts: List<DashboardPostStat>,
val risingPosts: List<DashboardPostStat>,
val stalePopularPosts: List<DashboardPostStat>,
val recentPosts: List<DashboardPostSummary>,
val recentComments: List<AdminDashboardCommentSummary>,
val categoryStats: List<DashboardCategoryStat>,
val actionItems: DashboardActionItems
)