From 2a0ee1d2cc2093e37cee1cf6041de1f9f4944347 Mon Sep 17 00:00:00 2001 From: joungmin Date: Wed, 11 Mar 2026 16:10:21 +0900 Subject: [PATCH] =?UTF-8?q?=EC=B1=84=EB=84=90=20=EC=B9=B4=EB=93=9C=20?= =?UTF-8?q?=ED=95=84=ED=84=B0=20UI,=20=EC=BA=90=EC=8B=9C=20=EC=B4=88?= =?UTF-8?q?=EA=B8=B0=ED=99=94,=20=EB=82=98=EB=9D=BC=20=ED=95=84=ED=84=B0?= =?UTF-8?q?=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 채널 설명/태그 DB 컬럼 추가 및 백오피스 편집 기능 - 채널 드롭다운을 유튜브 아이콘 토글 카드로 변경 (데스크톱 최대 4개 표시, 스크롤) - 모바일 홈탭 채널 카드 가로 스크롤 - region "나라" 값 필터 옵션에서 제외 - 관리자 캐시 초기화 버튼 및 API 추가 Co-Authored-By: Claude Opus 4.6 --- .../controller/AdminCacheController.java | 25 +++++ .../tasteby/controller/ChannelController.java | 8 ++ .../main/java/com/tasteby/domain/Channel.java | 2 + .../com/tasteby/mapper/ChannelMapper.java | 4 + .../com/tasteby/service/ChannelService.java | 4 + .../mybatis/mapper/ChannelMapper.xml | 9 +- frontend/src/app/admin/page.tsx | 82 ++++++++++++-- frontend/src/app/page.tsx | 104 ++++++++++++------ frontend/src/lib/api.ts | 15 +++ 9 files changed, 211 insertions(+), 42 deletions(-) create mode 100644 backend-java/src/main/java/com/tasteby/controller/AdminCacheController.java diff --git a/backend-java/src/main/java/com/tasteby/controller/AdminCacheController.java b/backend-java/src/main/java/com/tasteby/controller/AdminCacheController.java new file mode 100644 index 0000000..5da26b4 --- /dev/null +++ b/backend-java/src/main/java/com/tasteby/controller/AdminCacheController.java @@ -0,0 +1,25 @@ +package com.tasteby.controller; + +import com.tasteby.security.AuthUtil; +import com.tasteby.service.CacheService; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +@RestController +@RequestMapping("/api/admin") +public class AdminCacheController { + + private final CacheService cacheService; + + public AdminCacheController(CacheService cacheService) { + this.cacheService = cacheService; + } + + @PostMapping("/cache-flush") + public Map flushCache() { + AuthUtil.requireAdmin(); + cacheService.flush(); + return Map.of("ok", true); + } +} diff --git a/backend-java/src/main/java/com/tasteby/controller/ChannelController.java b/backend-java/src/main/java/com/tasteby/controller/ChannelController.java index a0df250..f33a1db 100644 --- a/backend-java/src/main/java/com/tasteby/controller/ChannelController.java +++ b/backend-java/src/main/java/com/tasteby/controller/ChannelController.java @@ -76,6 +76,14 @@ public class ChannelController { return result; } + @PutMapping("/{id}") + public Map update(@PathVariable String id, @RequestBody Map body) { + AuthUtil.requireAdmin(); + channelService.update(id, body.get("description"), body.get("tags")); + cache.flush(); + return Map.of("ok", true); + } + @DeleteMapping("/{channelId}") public Map delete(@PathVariable String channelId) { AuthUtil.requireAdmin(); diff --git a/backend-java/src/main/java/com/tasteby/domain/Channel.java b/backend-java/src/main/java/com/tasteby/domain/Channel.java index cb84f50..ab68a42 100644 --- a/backend-java/src/main/java/com/tasteby/domain/Channel.java +++ b/backend-java/src/main/java/com/tasteby/domain/Channel.java @@ -14,6 +14,8 @@ public class Channel { private String channelId; private String channelName; private String titleFilter; + private String description; + private String tags; private int videoCount; private String lastVideoAt; } diff --git a/backend-java/src/main/java/com/tasteby/mapper/ChannelMapper.java b/backend-java/src/main/java/com/tasteby/mapper/ChannelMapper.java index 1d67a35..448f626 100644 --- a/backend-java/src/main/java/com/tasteby/mapper/ChannelMapper.java +++ b/backend-java/src/main/java/com/tasteby/mapper/ChannelMapper.java @@ -21,4 +21,8 @@ public interface ChannelMapper { int deactivateById(@Param("id") String id); Channel findByChannelId(@Param("channelId") String channelId); + + void updateDescriptionTags(@Param("id") String id, + @Param("description") String description, + @Param("tags") String tags); } diff --git a/backend-java/src/main/java/com/tasteby/service/ChannelService.java b/backend-java/src/main/java/com/tasteby/service/ChannelService.java index 599239c..a37cc99 100644 --- a/backend-java/src/main/java/com/tasteby/service/ChannelService.java +++ b/backend-java/src/main/java/com/tasteby/service/ChannelService.java @@ -38,4 +38,8 @@ public class ChannelService { public Channel findByChannelId(String channelId) { return mapper.findByChannelId(channelId); } + + public void update(String id, String description, String tags) { + mapper.updateDescriptionTags(id, description, tags); + } } diff --git a/backend-java/src/main/resources/mybatis/mapper/ChannelMapper.xml b/backend-java/src/main/resources/mybatis/mapper/ChannelMapper.xml index 1d486fe..4752508 100644 --- a/backend-java/src/main/resources/mybatis/mapper/ChannelMapper.xml +++ b/backend-java/src/main/resources/mybatis/mapper/ChannelMapper.xml @@ -7,12 +7,14 @@ + + SELECT id, channel_id, channel_name, title_filter FROM channels diff --git a/frontend/src/app/admin/page.tsx b/frontend/src/app/admin/page.tsx index 96f3a80..f39f2f8 100644 --- a/frontend/src/app/admin/page.tsx +++ b/frontend/src/app/admin/page.tsx @@ -7,6 +7,33 @@ import { useAuth } from "@/lib/auth-context"; type Tab = "channels" | "videos" | "restaurants" | "users" | "daemon"; +function CacheFlushButton() { + const [flushing, setFlushing] = useState(false); + + const handleFlush = async () => { + if (!confirm("Redis 캐시를 초기화하시겠습니까?")) return; + setFlushing(true); + try { + await api.flushCache(); + alert("캐시가 초기화되었습니다."); + } catch (e) { + alert("캐시 초기화 실패: " + (e instanceof Error ? e.message : e)); + } finally { + setFlushing(false); + } + }; + + return ( + + ); +} + export default function AdminPage() { const [tab, setTab] = useState("channels"); const { user, isLoading } = useAuth(); @@ -38,9 +65,12 @@ export default function AdminPage() { 읽기 전용 )} - - ← 메인으로 - +
+ {isAdmin && } + + ← 메인으로 + +