diff --git a/docs/deploy.md b/docs/deploy.md
index 7d0d629..57829f1 100644
--- a/docs/deploy.md
+++ b/docs/deploy.md
@@ -64,7 +64,7 @@ sh scripts/migrate-production-db.sh status
v1.11.0은 `base-uri`, `object-src`, `frame-ancestors`만 강제한다. 광고 코드, 사용자 사이트 코드, 외부 이미지·미디어·iframe에 영향을 줄 수 있는 출처 정책은 계속 Report-Only이므로 기존 광고와 사용자 코드 실행을 차단하지 않는다. 전체 HTML 문서 `/pages/**`는 강제 CSP에서 제외하고 Report-Only 보고만 유지한다.
-배포 후 관리자 대시보드의 `CSP 관찰` 표 또는 `csp_violation_aggregates`의 `policy_version='compat-v1'`, `effective_directive`, `blocked_origin`, `document_path`, `user_agent_family`, `violation_count`, `last_seen_at`을 관찰한다. URL 쿼리·fragment·차단 자산 경로와 User-Agent 원문은 저장되지 않는다. `empty`, `about:`, 브라우저 확장 프로그램 scheme은 실제 외부 origin 허용 후보가 아니라 브라우저·확장 프로그램·빈 iframe 계열 신호로 본다. `허용 후보`는 지시어별 외부 origin을 빠르게 묶어 보여주는 보조 정보일 뿐이므로, 반복 위반이 광고·사이트 코드의 정상 출처인지 확인한 뒤에만 강제 정책 확대를 별도 배포한다.
+배포 후 관리자 진단 API `/admin/api/security/csp-violations` 또는 `csp_violation_aggregates`의 `policy_version='compat-v1'`, `effective_directive`, `blocked_origin`, `document_path`, `user_agent_family`, `violation_count`, `last_seen_at`을 관찰한다. URL 쿼리·fragment·차단 자산 경로와 User-Agent 원문은 저장되지 않는다. `empty`, `about:`, 브라우저 확장 프로그램 scheme은 실제 외부 origin 허용 후보가 아니라 브라우저·확장 프로그램·빈 iframe 계열 신호로 본다. `허용 후보`는 지시어별 외부 origin을 빠르게 묶어 보여주는 보조 정보일 뿐이므로, 반복 위반이 광고·사이트 코드의 정상 출처인지 확인한 뒤에만 강제 정책 확대를 별도 배포한다.
v1.12.21은 `최근 관찰 항목 누적` 표기로 집계 의미를 바로잡는다. 이는 최근 30일 발생 건수가 아니라 최근 보고된 행의 전체 누적값이다. `empty`·`unknown`만으로 iframe 보고의 원인을 확정하지 않는다. 현재 정책은 HTTPS 출처를 폭넓게 허용하므로 후보 부재를 정상 출처 조사 완료로 해석하지 않는다. 이번 변경은 관리자 UI·설명 개선으로 DB 마이그레이션이나 CSP 강제 정책 변경은 없다.
diff --git a/docs/history.md b/docs/history.md
index c9ae65e..be47a56 100644
--- a/docs/history.md
+++ b/docs/history.md
@@ -1,3 +1,9 @@
+## 2026-10-21 v1.12.23 — 대시보드는 최근 활동 요약, 멤버 이력은 탭으로 나눈다
+
+대시보드는 새 댓글의 게시물·작성자·시각을 빠르게 파악하도록 최근 댓글을 작은 한 줄 목록으로 줄이고 CSP 관찰 표와 주기 조회를 제거한다. 이는 관리자 화면 정리이며, 제공된 누적 보고로 보안 정책 강화 여부를 확정한 결정은 아니다. 기존 수집·집계와 보안 헤더는 유지한다.
+
+멤버 정보에 전체 댓글을 함께 표시하면 기본 정보 확인이 어려워지므로 정보·작성한 글·작성한 댓글 탭으로 구분한다. 작성 글은 기존 `posts.author_id`를 사용하고, 글과 댓글 모두 서버에서 작성자별 전체 이력을 검색·페이지 조회한다. 정보 폼은 탭을 옮겨도 유지해 미저장 입력이 사라지지 않도록 한다.
+
## 2026-10-21 v1.12.22 — 관리자 댓글 목록은 공개 조회와 분리한다
관리자는 회원별 작성 이력과 최근 댓글을 게시물 상태에 관계없이 확인해야 하므로 관리자 세션 전용 페이지 조회 API를 둔다. 공개 댓글 API의 접근 정책을 유지하고, 공통 목록 컴포넌트를 멤버 상세와 대시보드에서 재사용한다. 댓글 본문은 텍스트로 표시하고 게시물 편집과 공개 댓글 영역 이동을 구분한다.
diff --git a/docs/map.md b/docs/map.md
index 433acc2..ff66741 100644
--- a/docs/map.md
+++ b/docs/map.md
@@ -312,7 +312,7 @@
| components/admin/AdminMarkdownEditor.vue | 관리자 글 Markdown-first 에디터, 라이브·소스 모드 `/` 슬래시 명령(`/표` 기본 표 템플릿 포함, 후보 없는 슬래시 입력은 일반 줄바꿈·커서 이동 허용)·미디어 모달 선택 결과 본문 삽입(이미지·갤러리·비디오·오디오·파일), 코드 블록 본문 슬래시 명령 비활성화, 커서 블록 컨텍스트·선택 텍스트 색상 컨텍스트 `block-panel` emit, 소스 모드 입력 직후 textarea 최신 본문 기준 커서 논리 줄·블록 컨텍스트 갱신, 에디터 본문 `Cmd/Ctrl+Z` 히스토리와 선택 위치 복원, 라이브 이미지 설정 패널·이미지↔갤러리 드래그 변환(`merge-images-to-gallery`·`insert-image-to-gallery`·`extract-gallery-image`), 소스·라이브 `Cmd+Shift+K` 줄 삭제, 소스·라이브 `Cmd/Ctrl+K` 링크 삽입, 코드·콜아웃·토글 내부 줄 삭제, 라이브 fenced 블록 현재 닫는 줄 기준 교체, 블록 패널 바깥 클릭·지원 블록 밖 커서 이동 시 닫기·미디어 모달 중 유지, 슬래시 메뉴 위치·슬래시 명령 실행·공통 포커스·블록 패널 옵션 적용·라이브 미리보기 이벤트 적용 composable 연결, 인용 마지막 줄 아래 방향키 외부 문단 포커스 이동, 인용·콜아웃·코드·토글 선언 줄 옵션 수정, IME 조합 중 현재 블록 범위 안에서만 블록 패널 유지, 소스 모드 wrap 라인 번호 보정·라이브↔소스 위치 복원(코드·콜아웃·토글 선언 줄은 본문 줄로 보정), 라이브 슬래시 명령 후 포커스 복원 지연·미디어 명령 원문 줄 재반영 방지 |
| components/admin/AdminEditorBlockPanel.vue | 게시물 설정 사이드바 오버레이 블록 설정(선택 텍스트 색상, 단일 이미지 대표 너비 셀렉트(전체·갤러리 2장 1칸·갤러리 3장 1칸·갤러리 3장 2칸·직접 입력)·직접 너비·이미지·갤러리·링크·iframe·HTML·인용 배경색·콜아웃 제목·아이콘 ON/OFF 토글·비활성 아이콘 영역·배경색·코드 언어 셀렉트·줄번호 ON/OFF 토글·토글), 갤러리 선택 이미지 강조 |
| components/admin/AdminTagForm.vue | 관리자 태그 생성/수정 폼(이름/슬러그/설명/색상, 태그 헤더 이미지 업로드·삭제, 오버레이 제목·본문 편집, 수정 화면 변경 저장 버튼 변경사항 기준 활성화) |
-| components/admin/AdminMemberForm.vue | 관리자 멤버 추가/수정 폼(Ghost형 3분할, 기존 회원 보기/수정 모드 분리, 요약 1fr·입력 2fr, 원형 썸네일 hover 등록·변경·삭제, 기본 정보·레이블·관리자 노트·Google 로그인 연동 상태·활동 요약·멤버별 댓글 페이지 목록, 설정 메뉴의 비밀번호 변경·멤버 삭제 모달, 소유자 전용 Google 연동 해제 모달, 저장 토스트, 미저장 변경사항 이탈 확인) |
+| components/admin/AdminMemberForm.vue | 관리자 멤버 추가/수정 폼(Ghost형 3분할, 기존 회원 보기/수정 모드 분리, 요약 1fr·입력 2fr, 원형 썸네일 hover 등록·변경·삭제, 기본 정보·레이블·관리자 노트·Google 로그인 연동 상태·활동 요약·정보/작성한 글/작성한 댓글 탭·전체 이력 검색 및 번호형 페이지네이션, 설정 메뉴의 비밀번호 변경·멤버 삭제 모달, 소유자 전용 Google 연동 해제 모달, 저장 토스트, 미저장 변경사항 이탈 확인) |
| components/admin/AdminUnsavedChangesModal.vue | 관리자 편집 화면 공통 미저장 변경사항 이탈 확인 모달(상단 40px 위치) |
| components/admin/AdminConfirmModal.vue | 관리자 공통 확인 모달(제목·본문 슬롯·확인/취소 버튼, primary/danger 톤) |
| components/admin/AdminModalFrame.vue | 관리자 공통 일반 모달 프레임(오버레이, dialog 접근성 속성, 기본 패널 스타일, 바깥 클릭 닫기) |
@@ -366,7 +366,7 @@
| 파일 | 화면 |
|------|------|
-| pages/admin/index.vue | 대시보드(최근 댓글 5개·작성자/게시물 이동·30초 갱신, 상단 요약: 현재 접속자·오늘 방문자·누적 방문자·게시물 수, 일일·주간·월간·년간 선택형 방문자수·평균 체류·50% 스크롤 차트, 차트 막대 클릭 시 하단 선택 기간 상세 갱신, 자동 갱신 중 선택 기간 유지, 선택 기간 기준 왼쪽 인기 게시물·인기 페이지와 오른쪽 유입원·모바일/PC 묶음 디바이스(상위 기기별 방문자·조회·비율 한 줄 요약, OS별 방문자·비율), IP·줄바꿈된 열린 페이지 수·열린 페이지 목록 포함 접속자 목록, CSP 관찰 목적·집계 의미·정책 한계 안내와 상위 보고) |
+| pages/admin/index.vue | 대시보드(최근 댓글 5개 작은 행·게시글/작성자/시각/한 줄 내용·30초 갱신, 상단 요약: 현재 접속자·오늘 방문자·누적 방문자·게시물 수, 일일·주간·월간·년간 선택형 방문자수·평균 체류·50% 스크롤 차트, 차트 막대 클릭 시 하단 선택 기간 상세 갱신, 자동 갱신 중 선택 기간 유지, 선택 기간 기준 왼쪽 인기 게시물·인기 페이지와 오른쪽 유입원·모바일/PC 묶음 디바이스(상위 기기별 방문자·조회·비율 한 줄 요약, OS별 방문자·비율), IP·줄바꿈된 열린 페이지 수·열린 페이지 목록 포함 접속자 목록) |
| pages/admin/login.vue | 관리자 로그인, 일반 로그인과 같은 다크 인증 스타일·우측 배치 및 내부 오른쪽 정렬 폼, 이메일·비밀번호 모두 입력 시에만 제출 버튼 활성 |
| pages/admin/posts/index.vue | 글 목록, 본문 없는 `/admin/api/posts?paged=true` 페이지 응답 사용, 서버 검색·필터(상태·검색형 태그 combobox·추천·정렬)와 번호형 페이지네이션, `F`/`ㄹ` 검색창 포커스, 관리자 전용 상단 고정 배지·정렬·행 메뉴 토글, 헤더 우측 «새 글» 배치, 예약/초안/공개/멤버십/비공개 텍스트 상태, 추천 표시와 제목 사이 `featuredImageThumbnail` 우선 대표 이미지 썸네일, 별도 댓글 수 열, 제목 아래 주소·공개 보기 hover 아이콘, 백링크 개수 열과 고정 크기 참조 게시물 목록 모달·내부 검색·이동 아이콘, 별도 조회수 열의 누적 조회수·통계 모달 버튼, 적용 태그 전체 색상 배지, 화면 기준 행 more vert 메뉴(고정 전용 API·추천 전용 API·삭제 전 참조 경고·삭제) |
| pages/admin/posts/new.vue | 글 작성, Ghost 스타일 작성 폼, 초안 `POST` 디바운스 자동 저장·첫 저장 준비 오버레이·첫 생성 중 추가 입력 PUT 반영·이탈 직전 플러시, 저장 토스트 |
@@ -568,7 +568,7 @@
| server/routes/admin/api/analytics/realtime.get.js | 관리자 실시간 접속자 API |
| server/routes/admin/api/analytics/traffic.get.js | 관리자 유입원·디바이스·키워드 통계 API |
| server/routes/admin/api/analytics/range-detail.get.js | 관리자 통계 추이 날짜·구간 상세 API |
-| server/routes/admin/api/security/csp-violations.get.js | 관리자 대시보드 CSP Report-Only 위반 관찰 요약 API |
+| server/routes/admin/api/security/csp-violations.get.js | 관리자 진단용 CSP Report-Only 집계 요약 API(대시보드 조회 제거) |
| server/routes/admin/api/adsense/summary.get.js | 관리자 대시보드 AdSense 예상 수익·페이지뷰·노출·클릭 요약 API |
| plugins/site-analytics.client.js | 공개 라우트 pageview·heartbeat·read 클라이언트 전송 |
| plugins/bfcache-page-restore.client.js | 뒤로가기 캐시(bfcache) 복원 시 라우터 경로와 실제 URL 어긋남을 감지해 새로고침(HTML 문서 모드 페이지 이동 후 뒤로가기 잔상 방지) |
@@ -638,7 +638,9 @@
| tests/markdown-html-block.test.js | 게시물 HTML sanitizer 공격 우회·허용 HTML 회귀 테스트 |
| tests/multipart-file-upload.test.js | 다중 multipart 디스크 스트리밍·파일 크기 제한 회귀 테스트 |
| docker-compose.yml | NAS 컨테이너 실행 초안, PostgreSQL 호스트 기본 loopback 바인딩 |
-| components/admin/AdminCommentList.vue | 멤버별 댓글 10개 페이지 목록·대시보드 최신 댓글 5개·게시물/작성자 이동·조회 오류 재시도 |
-| server/routes/admin/api/comments.get.js | 관리자 댓글 조회 인증·Zod query 검증 |
+| components/admin/AdminCommentList.vue | 대시보드 최신 댓글 5개 작은 목록·게시글/작성자/시각/한 줄 내용·30초 갱신·조회 오류 재시도 |
+| server/routes/admin/api/comments.get.js | 관리자 댓글 조회 인증·댓글 내용/게시물 제목 검색·Zod query 검증 |
| server/repositories/comment-repository.js | 공개 댓글 조회·작성·좋아요와 관리자 댓글 최신순 페이지 조회 |
-| tests/playwright/e2e/admin-comments.spec.js | 멤버 댓글 페이지 이동·게시물 링크·대시보드 최근 댓글·게시글 댓글 열 E2E 검증 |
+| tests/playwright/e2e/admin-comments.spec.js | 멤버 정보/작성 글/댓글 탭·검색·페이지 이동·원문 링크·작은 대시보드 댓글·CSP 제거·게시글 댓글 수 E2E 검증 |
+| components/admin/AdminMemberActivityList.vue | 회원별 작성 글·댓글 탭의 전체 이력 최신순 검색·번호형 페이지네이션·게시물 이동 |
+| server/routes/admin/api/members/[id]/posts.get.js | 관리자 회원 작성 글 조회 인증·Zod 검증·검색·페이지 API |
diff --git a/docs/spec.md b/docs/spec.md
index 0d4bad1..dd83625 100644
--- a/docs/spec.md
+++ b/docs/spec.md
@@ -68,7 +68,7 @@
- 호환 정책은 모든 경로에서 `Content-Security-Policy-Report-Only`로 유지한다. 사용자 사이트 코드·광고·외부 미디어를 차단하지 않은 채 script/style/img/font/media/frame/connect/worker/manifest 위반을 `/api/csp-report`로 보고하며 `Reporting-Endpoints`와 `Report-To`도 같은 origin 수집 주소를 가리킨다.
- `POST /api/csp-report`는 `application/csp-report`, `application/reports+json`, `application/json`, `application/*+json`만 허용하고 요청 본문은 32KB, Reporting API 배열은 최대 20건으로 제한한다. IP 원문을 보관하지 않는 해시 키 기준으로 분당 60회까지만 받는다.
- CSP 위반은 정책 버전, 쿼리·fragment를 제거한 문서 경로, 지시어, 경로·쿼리를 제거한 차단 origin, 브라우저 계열만 `csp_violation_aggregates`에 누적한다. 원문 URL과 User-Agent는 저장하지 않으며 저장 실패가 일반 응답을 실패시키지 않는다. 차단 출처가 비어 있으면 `empty`, `about:blank` 계열은 `about:`, 브라우저 확장 프로그램은 `chrome-extension:`·`moz-extension:`·`safari-web-extension:` 같은 scheme 단위로 분류한다.
-- 관리자 대시보드는 CSP Report-Only 위반 집계가 1건 이상 있을 때만 `CSP 관찰` 표를 표시한다. 표는 최근 30일 내 보고된 상위 항목의 지시어, 보고된 출처, 문서 경로, 브라우저 계열, 누적 횟수, 최근 관찰 시각을 보여준다. 횟수는 최초 수집부터 누적이며 실제 최근 30일 발생 수가 아니다. 관찰 목적과 차단 없이 보고만 수집한다는 설명, `empty`·`unknown`의 의미, HTTPS 출처를 폭넓게 허용하는 현재 정책의 관찰 한계를 안내한다. `script-src-elem`, `style-src-attr`, `child-src` 같은 세부 지시어는 각각 `script-src`, `style-src`, `frame-src` 후보로 묶고, `http(s)` origin만 허용 후보로 별도 표시한다. 후보가 없어도 안전성이나 정책 강화 가능성을 확정하지 않는다.
+- v1.12.23부터 대시보드의 CSP 관찰 표와 조회·자동 갱신은 제거한다. 기존 보안 헤더·Report-Only 수집·집계·관리자 진단 API는 유지한다. 누적 보고만으로 정책 강화 가능성을 확정하지 않는다.
### 홈 Featured (인덱스)
@@ -1089,10 +1089,15 @@ APP_PORT=43080
- 첫 커밋 이후 변경사항을 커밋할 때마다 패치 버전 증가
- 메이저/마이너 버전은 구조 변경 또는 기능 묶음 단위로 결정
-## 관리자 댓글 조회 (v1.12.22)
+## 관리자 댓글·회원 작성 이력 조회 (v1.12.23)
-- `GET /admin/api/comments`: 관리자 세션 필수. `memberId`(선택 UUID), `page`(기본 1, 1~1000000 정수), `pageSize`(기본 10, 1~100 정수). 잘못된 조건은 400, 미인증은 401.
+- `GET /admin/api/comments`: 관리자 세션 필수. `memberId`(선택 UUID), `q`(기본 빈 문자열, trim, 최대 200자, 댓글 내용·게시물 제목 부분 검색), `page`(기본 1, 1~1000000 정수), `pageSize`(기본 10, 1~100 정수). 잘못된 조건은 400, 미인증은 401.
- 응답 `{ items, pagination: { page, pageSize, total, pageCount } }`. 항목은 `id`, `body`, `status`, `parentId`, `createdAt`, `userId`, `username`, `postId`, `postTitle`, `postSlug`, `postStatus` 제공. 모든 상태의 댓글·답글 포함, 작성 시각·ID 내림차순. 범위 초과 페이지는 마지막 페이지로 보정.
-- 멤버 상세는 10개씩 이전·다음 이동. 대시보드는 전체 최신 댓글 5개를 30초마다 갱신. 조회 오류는 재시도, 조회 중은 로딩 표시.
+- 멤버 상세는 `정보 / 작성한 글 / 작성한 댓글` 탭을 제공하며 정보로 진입한다. 정보 편집값은 탭 이동 시 유지한다. 이력은 선택한 탭에서만 조회하고, 10개씩 번호형 페이지네이션·검색 버튼/Enter로 검색한다. 검색 시 첫 페이지로 돌아가며 최신 작성순으로 전체 이력을 조회한다.
+- 대시보드는 최신 댓글 5개를 30초마다 갱신한다. 게시물·작성자·짧은 시각·말줄임 한 줄 내용만 작은 행으로 표시한다. 조회 오류는 재시도하며 이력 조회 중은 로딩 표시.
- 댓글 내용은 일반 텍스트로 표시. 작성자는 멤버 상세, 게시물 제목은 관리자 편집으로 이동. 공개·멤버십 글은 새 창의 `/post/:slug#comments` 링크 제공(공개 화면의 기존 접근 권한 적용).
- 게시글 목록 댓글 열은 기존 `commentCount` 사용. 공개 상태 댓글·답글만 집계.
+
+- `GET /admin/api/members/:id/posts`: 관리자 세션 필수. 회원 UUID와 `q`(trim, 최대 200자), `page`(1~1000000, 기본 1), `pageSize`(1~100, 기본 10) 검증. 잘못된 조건 400, 미인증 401.
+- 작성 글은 `posts.author_id`로 필터하고 초안·비공개·멤버십·공개 전체 포함, `created_at DESC, id DESC` 순서. `q`는 제목·주소·요약·본문의 문자 그대로 부분 검색이며 댓글 검색도 `%`, `_`를 와일드카드로 취급하지 않는다.
+- 작성 글 응답 `{ items: [{ id, title, slug, status, createdAt, publishedAt }], pagination: { page, pageSize, total, pageCount } }`. 범위 초과 페이지는 마지막으로 보정하고 미작성·검색 결과 없음은 빈 목록 반환.
diff --git a/docs/todo.md b/docs/todo.md
index 58f7917..902c7b7 100644
--- a/docs/todo.md
+++ b/docs/todo.md
@@ -4,7 +4,7 @@
## 2차 관리자 개발
-- `npm run test:api`의 기존 미디어 카탈로그 회귀 실패 조사: `core-api.spec.js`의 프로필 이미지 `usage`에 `type=user`가 없어 `typeLabel` 확인 실패. 댓글 API 검증은 통과. 격리 DB에서 사용처 계산·카탈로그 캐시 반영 순서 확인.
+- `npm run test:api`의 기존 미디어 카탈로그 회귀 실패 조사: `core-api.spec.js`의 프로필 이미지 `usage`에 `type=user`가 없어 `typeLabel` 확인 실패. 댓글·회원 작성 글 검색/페이지 API 검증은 통과. 격리 DB에서 사용처 계산·카탈로그 캐시 반영 순서 확인.
## 프론트엔드 개발
diff --git a/docs/update.md b/docs/update.md
index 4409ab4..1c4bf35 100644
--- a/docs/update.md
+++ b/docs/update.md
@@ -1,5 +1,15 @@
# 업데이트 이력
+## v1.12.23
+
+- 대시보드 CSP 관찰 표·조회·자동 갱신 제거.
+- 대시보드 최근 댓글을 게시글·작성자·시각·한 줄 내용의 작은 목록으로 축소.
+- 멤버 상세 정보·작성한 글·작성한 댓글 탭 분리.
+- 회원 작성 글·댓글 전체 이력 최신순 검색·번호형 페이지네이션 추가.
+- 댓글 내용·게시물 제목 검색과 작성 글 제목·주소·본문 검색 API 추가.
+- JavaScript 문법 검사·단위 테스트 273건·프로덕션 빌드·Chromium E2E 11건 검증 진행.
+- API 통합 검증 11건 통과, 기존 미디어 사용처 검증 실패 1건·후속 미실행 1건 유지.
+
## v1.12.22
- 관리자 멤버 상세에 최신순 댓글·답글 목록과 서버 페이지네이션 추가.
diff --git a/package-lock.json b/package-lock.json
index 5e6a570..efb0d68 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "sori.studio",
- "version": "1.12.22",
+ "version": "1.12.23",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "sori.studio",
- "version": "1.12.22",
+ "version": "1.12.23",
"hasInstallScript": true,
"dependencies": {
"@nuxtjs/tailwindcss": "^6.14.0",
diff --git a/package.json b/package.json
index 5e5955f..500a73a 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "sori.studio",
- "version": "1.12.22",
+ "version": "1.12.23",
"private": true,
"type": "module",
"imports": {
diff --git a/pages/admin/index.vue b/pages/admin/index.vue
index 4d13f2e..baa7a7f 100644
--- a/pages/admin/index.vue
+++ b/pages/admin/index.vue
@@ -94,23 +94,6 @@ const {
})
})
-const {
- data: cspViolationSummary,
- refresh: refreshCspViolationSummary
-} = await useFetch('/admin/api/security/csp-violations', {
- query: { days: 30, limit: 8 },
- server: false,
- default: () => ({
- days: 30,
- totalViolations: 0,
- totalRows: 0,
- recentViolations: 0,
- latestSeenAt: null,
- topViolations: [],
- allowlistCandidates: []
- })
-})
-
const todayKey = getAnalyticsDayKey()
const publishedCount = computed(() => posts.value.filter((post) => post.status === 'published').length)
const draftCount = computed(() => posts.value.filter((post) => post.status === 'draft').length)
@@ -203,10 +186,6 @@ const chartPagination = computed(() => {
const adsenseCards = computed(() => adsenseSummary.value.periods || [])
const adsenseBalance = computed(() => adsenseSummary.value.balance || createEmptyAdsenseBalance())
-const cspViolations = computed(() => cspViolationSummary.value?.topViolations || [])
-const cspAllowlistCandidates = computed(() => cspViolationSummary.value?.allowlistCandidates || [])
-const hasCspViolations = computed(() => Number(cspViolationSummary.value?.totalViolations || 0) > 0)
-
/**
* AdSense 통화 코드를 표시 가능한 값으로 보정한다.
* @returns {string} 통화 코드
@@ -266,29 +245,6 @@ const formatAdsenseRpm = (value, currencyCode = '') => {
}).format(Number(value || 0))
}
-/**
- * ISO 날짜를 관리자 대시보드용 시각으로 변환한다.
- * @param {string | null | undefined} value - ISO 날짜
- * @returns {string} 표시 문자열
- */
-const formatDashboardDateTime = (value) => {
- if (!value) {
- return '-'
- }
-
- const date = new Date(value)
- if (Number.isNaN(date.getTime())) {
- return '-'
- }
-
- return new Intl.DateTimeFormat('ko-KR', {
- month: '2-digit',
- day: '2-digit',
- hour: '2-digit',
- minute: '2-digit'
- }).format(date)
-}
-
/**
* 통계 차트 이전 기간으로 이동한다.
* @returns {void}
@@ -665,7 +621,6 @@ onMounted(() => {
refreshSummary()
refreshTrendDetail()
refreshRealtime()
- refreshCspViolationSummary()
}, 30000)
})
@@ -722,7 +677,7 @@ watch(trendRows, () => {
-
+
- {{ recent ? '최근 댓글' : '작성한 댓글' }} - 전체 {{ data?.pagination.total || 0 }}개 · 답글 포함 -
-댓글을 불러오는 중입니다.
-작성한 댓글이 없습니다.
---
-
- {{ comment.username }}
-
- 답글
- {{ comment.status === 'pending' ? '승인 대기' : '차단됨' }}
-
-
- {{ comment.postTitle || '(제목 없음)' }}
- 게시물 보기
- 미공개 게시물
-
+
+
{{ comment.body }}
-최근 댓글 · 전체 {{ data?.pagination.total || 0 }}개
++ 댓글을 불러오지 못했습니다. +
+작성한 댓글이 없습니다.
++-
+
{{ comment.postTitle || '(제목 없음)' }}
+ {{ comment.postTitle || '(제목 없음)' }}
+ {{ comment.username }}
+
+
-{{ comment.body }}