From c3bbb4e9599b9e160bc4e77d510e2f50881196da Mon Sep 17 00:00:00 2001
From: th-kim0823
Date: Mon, 27 Apr 2026 20:15:25 +0900
Subject: [PATCH] =?UTF-8?q?feat:=20admin=20=EC=A3=BC=EC=A0=9C=20=ED=8E=B8?=
=?UTF-8?q?=EC=A7=91=20=E2=80=94=20JSON=20=EC=A7=81=EC=A0=91=20=ED=8E=B8?=
=?UTF-8?q?=EC=A7=91=20+=20=EA=B2=80=EC=A6=9D?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Co-Authored-By: Claude Sonnet 4.6
---
app.py | 38 +++++++++++++++++++++++++++++++++++---
1 file changed, 35 insertions(+), 3 deletions(-)
diff --git a/app.py b/app.py
index 6b58437..bccce16 100644
--- a/app.py
+++ b/app.py
@@ -710,9 +710,41 @@ def render_admin():
update_topics(new_cats)
st.success("저장됨. 큰 화면 다음 갱신 시 반영.")
st.rerun()
- # JSON 모드는 T14에서 추가 (else branch는 placeholder)
- else:
- st.info("Task 14에서 JSON 직접 편집 모드 추가됨.")
+ else: # JSON 직접 편집
+ current_json = json.dumps(
+ {"categories": cur_topics}, ensure_ascii=False, indent=2
+ )
+ edited = st.text_area(
+ "topics JSON",
+ value=current_json,
+ height=400,
+ key="topics_json_editor",
+ )
+ jc1, jc2 = st.columns(2)
+ with jc1:
+ if st.button("JSON 검증"):
+ try:
+ parsed = json.loads(edited)
+ cats = parsed.get("categories", [])
+ if not isinstance(cats, list):
+ st.error("'categories'는 list 여야 합니다.")
+ else:
+ st.success(f"OK — {len(cats)}개 카테고리")
+ except json.JSONDecodeError as e:
+ st.error(f"JSON 파싱 실패: {e}")
+ with jc2:
+ if st.button("JSON 저장", type="primary"):
+ try:
+ parsed = json.loads(edited)
+ cats = parsed.get("categories", [])
+ if not isinstance(cats, list):
+ st.error("'categories'는 list 여야 합니다.")
+ else:
+ update_topics(cats)
+ st.success("저장됨.")
+ st.rerun()
+ except json.JSONDecodeError as e:
+ st.error(f"저장 실패 — JSON 파싱 에러: {e}")
st.divider()