어드민 대시보드 전면 정비 · SNS 발행 버튼 분리 · 정렬/썸네일 버그 수정
어드민 쓰기 편하게 갈아엎고, 오래된 버그 두 개를 잡은 날입니다.
어드민 전역 UI 정비
어드민 페이지들이 그동안 각자 따로 만들어지면서 헤더 구조도 제각각이었고, 다른 섹션(디자인/게임즈/크리에이티브/채널)으로 넘어가려면 매번 새 탭을 열거나 URL을 직접 쳐야 했습니다. 두 개 컴포넌트로 정리했습니다.
SectionShortcuts: 네 개 섹션으로 바로 이동하는 버튼 묶음. 평소엔 무채색이다가 호버하면 각 섹션의 브랜드 컬러(디자인 네온그린, 게임즈 네온옐로우, 크리에이티브 시안, 채널 인디고)로 바뀌게 만들어서, 어디로 가는 버튼인지 호버 순간에만 알려주는 쪽을 택했습니다.
AdminActionsPanel: 카테고리 관리·배너 관리·게임즈 관리·애널리틱스·댓글 관리·퍼블리싱 관리로 가는 바로가기와 새 글쓰기 버튼을 묶은 우측 고정 패널. 원래 대시보드 홈에만 있던 걸 전체 어드민 페이지에 공통으로 깔았습니다. 지금 보고 있는 페이지는 그라데이션 채움으로 강하게 표시하고, 새 글쓰기 버튼은 일부러 그보다 약한 톤으로 낮춰서 "지금 어디 있는지"가 "새 글쓰기"보다 시각적으로 더 우선하게 만들었습니다. 순서는 드래그로 바꿀 수 있고 localStorage에 저장됩니다.
이 두 컴포넌트를 배포하면서 헤더도 페이지마다 다르던 걸(홈 아이콘 유무, "← 대시보드"/"← 어드민 홈"처럼 문구도 제각각) "← 어드민" 하나로 통일하고, 위치도 제목 바로 옆(좌측)으로 맞췄습니다.
같은 김에 각 페이지 안에서도 눈에 띄게 비어 있던 부분들을 채웠습니다 — 카테고리 관리의 탭·레이아웃 버튼과 수정/삭제 버튼에 호버 효과가 아예 없었던 것, 배너 관리의 파일 선택 버튼이 브라우저 기본 스타일 그대로라 다크 테마랑 안 어울리던 것, 애널리틱스의 기간 탭들이 활성 상태만 표시되고 호버는 안 먹던 것까지 정리했습니다.
인디고 퍼플 테마가 새고 있던 버그
어드민 페이지는 .admin-page 클래스가 --accent를 인디고 퍼플로 덮어써서 통일된 톤을 씁니다. 그런데 퍼블리싱 관리·애널리틱스 페이지는 이 클래스가 아예 안 붙어 있었습니다. 그러면 var(--accent)는 클래스가 없는 채로 상위 :root/.dark까지 올라가는데, 사이트 기본값이 디자인 섹션의 네온그린(#01FF75)이라 — 결과적으로 퍼블리싱 관리 페이지의 토글·버튼 색이 인디고가 아니라 디자인 그린으로 새고 있었습니다. .admin-page 클래스를 붙이고, 하드코딩돼 있던 인디고 값(#6366f1, #4f46e5)도 전부 var(--accent)로 바꿔서 진짜로 테마에서 상속받게 고쳤습니다.
카테고리 사이드바 그룹핑
대시보드 좌측 카테고리 목록이 실제 운영 중인 카테고리 수만큼 그냥 쭉 나열되고 있어서 스크롤이 꽤 길었습니다. categorySectionMap을 기준으로 디자인/게임즈/크리에이티브/채널 대분류로 묶고, 평소엔 다 접혀 있다가 클릭하면 펼쳐지는 아코디언으로 바꿨습니다. 지금 필터링 중인 카테고리가 있으면 그 카테고리가 속한 그룹만 자동으로 펼쳐진 채 시작합니다. 각 카테고리 옆에는 groupBy로 집계한 실제 게시글 수도 흰 숫자로 붙여서, 몇 개나 있는지 목록만 봐도 알 수 있게 했습니다.
SNS 동시발행 — 별도 버튼으로 분리, 핀터레스트 발행 안 되던 문제
SNS 동시발행 기능이 "발행하기" 버튼 클릭에 그대로 묶여 있었습니다. 발행 시점에 SNS 체크박스가 하나라도 선택돼 있으면 자동으로 크로스포스팅을 시도하고, 아니면 그냥 조용히 넘어가는 구조였는데, 이 "조용히 넘어감"이 실제로 문제를 일으켰습니다. 핀터레스트에 글이 안 올라왔다는 제보를 받고 확인해보니, 성공/실패 안내 모달 자체가 뜬 적이 없었습니다 — 즉 API 호출이 아예 안 나갔다는 뜻이고, 원인은 발행 버튼을 누르는 시점에 체크박스 선택 상태가 비어 있었던 것이었습니다. SNS 대상 선택은 저장 때마다 초기화되는 휘발성 상태라, 체크했다고 생각했는데 실제로는 안 눌려 있었거나 페이지를 다시 열면서 풀린 경우 이런 식으로 아무 신호 없이 건너뛰어질 수 있는 구조였습니다.
"발행하기"에서 SNS 로직을 완전히 떼어내고, SNS 동시발행 카드 안에 별도의 "SNS로 발행" 버튼을 새로 만들었습니다. 이미 저장·발행된 글이어야 활성화되고, 플랫폼을 하나도 안 골랐으면 버튼 자체가 비활성 상태로 안내 문구와 함께 멈춰 있어서, 이번처럼 조용히 건너뛰어지는 상황이 구조적으로 불가능해졌습니다.
원인 조사 과정에서 핀터레스트 어댑터 코드의 실제 버그도 하나 찾았습니다. 핀터레스트 description 필드는 500자 제한이 있는데, 코드는 안내 문구로만 500자를 언급할 뿐 실제로 자르지는 않고 있었습니다. 글이 길면 인스타그램(2,200자)은 성공하고 핀터레스트만 400 에러로 실패하는 상황이 딱 이 케이스였습니다. 500자 넘으면 자동으로 잘라 보내도록 고치고, 응답이 JSON이 아닐 때(502/504 등) 파싱 자체가 실패해서 원인이 가려지던 것도 방어 처리했고, 서버 로그에도 실패 원인이 남도록 했습니다. 실제로 반영 후 핀터레스트 발행이 정상 동작하는 것까지 확인했습니다.
게시글 목록 정렬이 이상하던 버그
어드민 목록을 날짜순으로 정렬했는데 2024년 글이 2026년 글보다 위에 뜨는 제보를 받았습니다. DB를 직접 열어보니 createdAt 컬럼에 두 가지 저장 형식이 섞여 있었습니다 — 대부분은 텍스트로 저장된 ISO 날짜였는데, 옛날 시딩 스크립트가 남긴 걸로 보이는 5개 글은 숫자(epoch 밀리초)로 저장돼 있었습니다. SQLite는 정렬할 때 타입을 먼저 비교합니다(NULL < 숫자 < 텍스트 순서). 그래서 ORDER BY createdAt DESC를 돌리면 텍스트로 저장된 행들이 실제 날짜와 무관하게 숫자로 저장된 행들보다 무조건 먼저 나와버립니다 — 날짜 값이 잘못된 게 아니라 저장 타입이 뒤섞여서 생긴 정렬 버그였습니다. 문제였던 6개 행(형식이 살짝 다르던 것 1개 포함)을 전부 정상 텍스트 형식으로 통일하는 마이그레이션을 돌려서 해결했습니다.
유튜브 썸네일이 안 잡히던 버그
본문 맨 앞에 유튜브 영상을 넣어도 썸네일로 안 쓰이고 본문 아무 데나 있는 이미지가 대신 쓰인다는 제보도 있었습니다. 썸네일 자동 감지 로직을 보니 "본문에 이미지 마크다운이 있으면 무조건 그걸 먼저 쓰고, 하나도 없을 때만 유튜브를 본다"는 순서로 짜여 있었습니다. 본문에서 실제로 어느 게 더 먼저 나오는지는 안 보고, 이미지 유무만 봤던 겁니다. 이미지와 유튜브 URL 둘 다 찾아서 각각의 등장 위치(match.index)를 비교하고, 본문에서 실제로 더 먼저 나오는 쪽을 썸네일로 쓰도록 고쳤습니다.
게임 게시판 배너
게임 카테고리 상단 배너 컴포넌트도 손을 봤습니다. 배너 이미지 위 그라데이션 오버레이 불투명도를 올려서 텍스트가 덜 묻히게 더 어둡게 만들었고, 배너와 아이콘의 border-radius를 14px에서 8px로 줄여서 너무 둥글어 보이던 느낌을 정리했습니다. 아이콘에는 클릭하면 해당 게시판으로 이동하는 링크와 호버 시 살짝 확대되는 효과를 추가했습니다. 게임즈 관리 페이지에서도 아이콘 이미지처럼 배너 이미지도 URL 입력뿐 아니라 파일 업로드·삭제가 되도록 맞췄습니다.
댓글
관련 게시글