Files
sori.studio/docs/map.md

579 lines
80 KiB
Markdown

# 파일-화면 매핑
> 현재 구현 기준으로 주요 파일과 화면·기능 연결을 정리한다.
## 레이아웃
| 파일 | 화면 |
|------|------|
| layouts/default.vue | 메인·목록·태그 — 3열 `gap`+중앙 `1fr`, `site-main` `max-w-[720px]`, 오른쪽 컬럼 전체 높이 구분선, 모바일 슬라이드 메뉴 |
| layouts/post.vue | 개별 게시물 — `default`와 동일, 오른쪽 컬럼 전체 높이 구분선 |
| layouts/admin.vue | 관리자 전체, 320px 밝은 Ghost형 사이드바(대시보드 `/admin` 활성 링크·사이트 보기 새 창·콘텐츠 구간 여백), 우측 전체 높이 캔버스, 멤버 수 표시, 하단 사용자 드롭다운·설정, `내 프로필` 멤버 편집 이동, 게시글 `+` 새 글 진입, 글 작성/수정 화면의 전체 화면 편집 모드와 문서 스크롤 잠금, **`/admin/settings`에서는 사이드바 숨김·본문 전체 화면·설정용 문서 스크롤 잠금** |
| layouts/page.vue | 고정 페이지 전체 화면 |
| app.vue | 공개 사이트 설정 기반 파비콘 head 링크, 페이지 제목이 있으면 제목만 쓰고 없으면 사이트 이름을 쓰는 title template, 브랜드 컬러 `--site-accent` 적용, 새 화면 렌더·BFCache 복귀 후 해제되는 불투명 전역 이동 로딩 오버레이 |
| error.vue | 공개 404/서버 오류 화면, 홈 이동 버튼 |
## Composables
| 파일 | 용도 |
|------|------|
| composables/formatPostDate.js | 공개 게시일 `YYYY.MM.DD`, 관리자·수정일 보조 `formatPostDateTime`, `wasPostUpdatedAfterPublish` |
| composables/createPostSummary.js | 게시물 요약·본문에서 목록·SEO용 짧은 설명 텍스트 생성, 본문 대체 요약의 표시용 마크다운·HTML 토큰 제거 |
| composables/useAdminToast.js | 관리자 우측 상단 토스트(성공·오류·안내; 모달보다 위 z-index) |
| composables/useImeSearchInput.js | 한글 등 IME 조합 중(`compositionupdate`)에도 검색어가 즉시 반영되는 검색 입력 처리기(표시값·`onInput`·`onCompositionEnd`, NFC 정규화·선택적 디바운스) |
| composables/useAdminSettingsNavigation.js | 관리자 설정 화면 내비게이션 검색·필터·활성 구역·스크롤 이동·스크롤 스파이 상태 |
| composables/useAdminPostTags.js | 관리자 게시물 폼 태그 파싱·추천·선택·삭제·키보드 처리 상태 |
| composables/useAdminFeaturedImagePicker.js | 관리자 게시물 폼 대표 이미지 선택 모달의 검색·페이지네이션·업로드·선택 상태 |
| composables/useAdminPostPublishState.js | 관리자 게시물 폼 발행·예약·발행취소 상태와 날짜 입력 상태 |
| composables/useAdminMarkdownSlashMenu.js | 관리자 Markdown 에디터 슬래시 메뉴 상태·검색 결과·억제 줄·키보드 탐색 타이머 관리 |
| composables/useAdminMarkdownHistory.js | 관리자 Markdown 에디터 undo/redo 스택·기록 그룹화·복원 중 상태 관리 |
| composables/useContentMarkdownBlocks.js | 공개 Markdown 본문 파싱·제목 ID·인아티클 광고 렌더 블록·하단 삽입 줄·라이트박스 대상 목록 계산 |
| composables/useContentMarkdownLightbox.js | 공개 Markdown 본문 단일 이미지·갤러리 통합 라이트박스 상태·좌우 이동·ESC 닫기·키보드 이벤트 연결 관리 |
| composables/useContentMarkdownImageDrag.js | 관리자 라이브 Markdown 본문의 단일 이미지·갤러리 드래그 상태, drop target 표시, 병합·삽입·분리·정렬 이벤트 중개 |
| composables/useContentMarkdownLiveSelection.js | 관리자 라이브 Markdown 본문의 Selection Bridge, 포커스 복원, line focus/blur, 원문 편집 표시 상태 관리 |
| composables/useContentMarkdownFencedBlocks.js | 관리자 라이브 Markdown 코드·콜아웃·토글 fenced 블록 편집 이벤트와 아래 문단 삽입 상태 관리 |
| composables/useContentMarkdownParagraphs.js | 관리자 라이브 Markdown 문단·스페이서 편집 이벤트와 문단 Enter 단축 변환 관리 |
| composables/useContentMarkdownLists.js | 관리자 라이브 Markdown 목록 번호 계산과 항목 커밋·분리·탈출 이벤트 관리 |
| composables/useContentMarkdownQuotes.js | 관리자 라이브 Markdown 인용 블록 커밋·아래 이탈·일반 문단 복귀 이벤트 관리 |
| composables/useAdminMediaThumbnailRegeneration.js | 관리자 미디어 화면 대표 이미지·페이지 커버·본문 이미지 재생성 가능 여부와 API 호출 상태 |
| composables/usePublicSiteSettings.js | 공개 화면의 `/api/site-settings` 조회 key(`site-settings-public`)와 기본 설정값 통일 |
## 공유 라이브러리(서버·클라이언트 공통)
| 파일 | 용도 |
|------|------|
| lib/upload-size-limit.js | 관리자 미디어 업로드 종류별 최대 바이트 판별·1회 파일 수/총량 제한 정규화·용량 문구(서버·클라이언트 공용) |
| lib/content-in-article-ad.js | 공개 Markdown 본문 인아티클 광고 삽입 후보·목표 위치 계산 |
| lib/content-gallery-images.js | 공개 Markdown 본문 단일 이미지·갤러리 라이트박스 목록 생성과 갤러리 행 분할 계산 |
| lib/content-image-urls.js | 공개 Markdown 본문 이미지 표시 URL·라이트박스 URL·srcset·갤러리 sizes 계산 |
| lib/admin-social-settings-section.js | 관리자 설정 SNS 설정 필드 목록·기본 스냅샷·정규화·스냅샷 복사·변경 비교 helper |
| lib/admin-post-settings-section.js | 관리자 설정 POST 설정 필드 목록·기본 스냅샷·정규화·스냅샷 복사·변경 비교 helper |
| lib/admin-spam-settings-section.js | 관리자 설정 스팸 필터 필드 목록·기본 스냅샷·정규화·textarea 변환·스냅샷 복사·변경 비교 helper |
| lib/admin-brand-settings-section.js | 관리자 설정 브랜드 설정 필드 목록·기본 스냅샷·정규화·스냅샷 복사·변경 비교 helper |
| lib/admin-announcement-settings-section.js | 관리자 설정 어나운스 바 설정 필드 목록·기본 스냅샷·정규화·스냅샷 복사·변경 비교 helper |
| lib/post-card-thumbnail-url.js | 게시물 카드 썸네일 `thumbs/*-card.webp`, Pages 커버 썸네일 `thumbs/*-page-cover.webp`, 본문 표시용 `body-1600`/`body-720`·라이트박스용 `body-2560` 파생 이미지 URL 판별과 레거시 `body`/`lightbox` 판별, 자동 생성 이미지 캐시 버전 URL 생성(대표 이미지·본문 이미지·갤러리·Pages 커버 선택 및 서버 검증 공용) |
| lib/external-favicon-url.js | 외부 URL origin 기준 Google `gstatic.com/faviconV2` 파비콘 URL 생성(내부 경로는 빈 문자열) |
| lib/navigation-url.js | 네비게이션 URL 접두사 분리·합성·정규화(`https://` 자동 보정, `/` 내부 경로) |
| lib/recommended-site-icon-url.js | 추천 사이트 아이콘 URL 우선순위(수동 썸네일 > 서버 캐시 > 외부 프록시) |
| lib/navigation-editor-tree.js | 관리자 메뉴 UI·서버 `renumberSortOrderByTree`가 쓰는 `buildNavigationEditorTree`, 관리자 상단 네비 평면 표용 `flattenNavigationEditorWrappers` |
| lib/markdown-content-normalizer.js | 관리자 Markdown-first 전환 후 레거시 블록 배열·객체 본문 값을 저장용 마크다운 문자열로 변환 |
| lib/markdown-editor-history.js | 관리자 Markdown-first 에디터 undo/redo 히스토리 항목 생성, 레거시 문자열 항목 본문 추출, 선택 범위 보정 |
| lib/markdown-editor-keyboard.js | 관리자 Markdown-first 에디터 전역 단축키 판별(Cmd/Ctrl 조합, undo/redo, 작성/미리보기 전환, 미디어 선택 닫기) |
| lib/markdown-editor-media.js | 관리자 Markdown-first 에디터 미디어 선택 모달의 미디어 종류 판별, 대상별 선택 가능 여부, 미리보기 URL, 업로드 MIME 허용, 선택 대상별 제목·accept·API kind·업로드 안내, 라이브러리 빈 상태 문구, 적용 버튼 상태, 선택 순서·토글·항목 해석, 업로드 오류·한도 검증, 페이지 상태·범위·페이지 번호 보정·페이지 번호 계산, fenced 미디어 블록 생성 |
| lib/markdown-block-parser.js | 공개 Markdown 본문 문자열을 제목·문단·이미지·갤러리·fenced 블록·인용·목록·코드·표 렌더링 블록으로 변환 |
| lib/markdown-block-context.js | 관리자 Markdown textarea·라이브 편집 포커스 위치 기준 이미지·갤러리·링크·iframe·HTML·인용·콜아웃·코드·토글 블록 설정 패널 대상 판별, 인용 옵션 공통 파서 연결, 코드 fenced 블록 여닫는 펜스 쌍 판별 |
| lib/markdown-iframe-embed.js | 게시물 본문 iframe 블록의 코드 판별과 안전 속성 추출, `allowfullscreen`을 `allow=fullscreen` 권한으로 정규화 |
| lib/markdown-html-block.js | 게시물 본문 HTML 블록의 parser 기반 허용 태그·속성 sanitizer, 실행 URL·인라인 style 제거와 새 창 링크 rel 보정 |
| lib/markdown-callout.js | 인용 막대 색상·콜아웃 배경색 옵션, 선언 줄 파싱·직렬화 |
| lib/markdown-fenced-meta.js | Markdown fenced 블록 시작·종료 줄 탐색, 본문 수집, 북마크·회원가입·미디어 메타 파싱 |
| lib/markdown-quote.js | 공개 Markdown 인용 줄 판별·옵션 파싱·라이브 편집 줄 변환 |
| lib/brand-color.js | 사이트 브랜드 컬러 기본값·hex 검증·정규화 |
| lib/markdown-image.js | 이미지 마크다운 직렬화·파싱, 단독 이미지 URL 판별 |
| lib/markdown-table.js | 공개 Markdown 표 행·구분선·정렬·블록 파싱 |
| lib/markdown-toc.js | 공개 게시글 TOC용 H1~H3 제목 추출과 앵커 ID 생성 |
| lib/markdown-slash-commands.js | 관리자 Markdown-first 에디터 슬래시 명령 목록과 삽입 줄 정의, 미디어 명령 action·모달 종류 판별, 슬래시 메뉴 제외 줄 Set·하이라이트 인덱스·방향키 순환 갱신·키보드 동작 분류, 미디어 명령 지연 commit 무시·슬래시 원문 줄 교체 삽입, 적용 후 포커스·textarea 선택 위치 계산 helper |
| lib/markdown-slash-menu-position.js | 관리자 Markdown-first 에디터 슬래시 메뉴 뷰포트 위치 보정 helper |
| lib/markdown-slash-menu-scroll.js | 관리자 Markdown-first 에디터 슬래시 메뉴 선택 항목 표시용 scrollTop 계산 helper |
| lib/markdown-inline.js | 공개·관리자 공통 인라인 마크다운 파서, 링크·굵게·기울임·인라인 코드·첨자·인라인 색상 토큰(`::color[텍스트]`) 변환, 링크·굵게·기울임·색상 내부 중첩 인라인 문법과 `<br>` 줄바꿈 처리, 라이브 멀티라인 본문의 기본 불릿/번호 목록 HTML 변환과 contenteditable 목록 마커 기준 커서 offset 계산·직렬화 |
| lib/post-tag-limit.js | 게시물별 태그 최대 개수 기본값·허용 범위·정규화 |
| lib/analytics-shared.js | 통계 추적 경로 필터·체류/스크롤 상수(클라이언트·서버 공용) |
| lib/analytics.js | 서버 전용 visitor/session hash(`node:crypto`) |
| lib/analytics-traffic.js | referrer·User-Agent 기반 유입원·디바이스·검색 키워드 축약 분류 |
| lib/admin-pagination.js | 관리자 번호형 페이지네이션 페이지 보정·ellipsis 항목 계산 |
| lib/csp-report.js | CSP 보고 Content-Type·32KB/20건 제한 상수, payload 검증, 문서 경로·차단 origin·브라우저 계열 최소화 |
| lib/site-route-transition.js | 공개 라우트 전환 베일 사용 여부와 query/hash 이동 제외, 스크롤 복원·최상단 이동 helper |
| lib/media-catalog.js | 업로드 URL·저장 키 정규화, 미디어 종류·원본/파생 역할 판별, 콘텐츠 미디어 참조 추출, PostgreSQL LIKE 리터럴 이스케이프 |
| lib/social-links.js | 사이트 설정 SNS 링크 아이콘 프리셋·사용자 SVG 정리·URL 자동 보정·레거시 JSON 문자열 복구·공개 노출 목록 생성 |
| server/utils/backup-storage-summary.js | 관리자 사이트 설정 백업 현황용 업로드 파일 스캔·원본/자동 생성 이미지/프로필/내보내기 파일 용량 집계 |
## 문서
| 파일 | 용도 |
|------|------|
| docs/shortcuts.md | 사이트 단축키, 작성 약어, 슬래시 명령, Markdown 약식 문법 정리 |
| docs/update-log/v1.0.md | 방문자용 업데이트 공지 초안(v0.0~v1.0) |
| docs/update-log/v1.1.md | 방문자용 업데이트 공지 초안(v1.0 개발 구간) |
| docs/update-log/v1.2.md | 방문자용 업데이트 공지 초안(v1.1 개발 구간) |
| docs/update-log/v1.5.md | 방문자용 업데이트 공지 초안(v1.2~v1.4 개발 구간) |
| docs/update-log/v1.6.md | 방문자용 업데이트 공지 초안(v1.5 개발 구간) |
| docs/update-log/v1.10.md | 방문자용 업데이트 공지 초안(v1.6~v1.9 개발 구간) |
| docs/update-log/v1.11.md | 방문자용 업데이트 공지 초안(v1.10 개발 구간) |
## Nuxt 모듈
| 파일 | 용도 |
|------|------|
| modules/nuxt-ssr-paths-write.mjs | `paths.mjs`를 `.nuxt`에 기록해 Node가 `#internal/nuxt/paths`를 해석할 수 있게 함 |
## Scripts
| 파일 | 용도 |
|------|------|
| scripts/check-js-syntax.js | `npm run lint`에서 JS/MJS/CJS 파일을 `node --check`로 문법 점검 |
| scripts/backfill-post-thumbnails.js | 게시물 대표 이미지 URL 기준 목록 카드용 WebP 썸네일 백필 |
| scripts/backfill-post-body-thumbnails.js | 게시물 본문 이미지 URL 기준 본문 표시용 WebP 썸네일 백필 |
| scripts/backfill-page-cover-thumbnails.js | 홈 Pages 진열장 커버 이미지 URL 기준 3:4 WebP 썸네일 백필 |
| scripts/backfill-post-thumbnails-production.sh | npm 없는 NAS 호스트에서 앱 컨테이너 내부 Node로 카드 썸네일 백필 실행 |
| scripts/backfill-post-body-thumbnails-production.sh | npm 없는 NAS 호스트에서 앱 컨테이너 내부 Node로 본문 표시용 WebP 백필 실행 |
| scripts/backfill-page-cover-thumbnails-production.sh | npm 없는 NAS 호스트에서 앱 컨테이너 내부 Node로 Pages 커버 썸네일 백필 실행 |
| scripts/generate-adsense-token.js | AdSense Management API refresh token 발급과 접근 가능한 계정 이름 확인 |
| scripts/run-playwright-tests.js | API/E2E 프로젝트별 격리 환경 준비·Playwright 실행·정리 |
| scripts/playwright-test-environment.js | `_test` PostgreSQL 컨테이너·임시 업로드 루트·worker 비활성화 환경 구성 |
| scripts/reconcile-media-catalog.js | loopback 비운영 DB만 허용하는 파일 비파괴 미디어 카탈로그 수동 reconcile |
## 테스트
| 파일 | 용도 |
|------|------|
| playwright.config.js | Playwright API/E2E 프로젝트, 단일 worker, 전용 Nuxt 서버·trace 설정 |
| docker-compose.test.yml | 실행마다 생성·폐기하는 PostgreSQL 16 테스트 DB·볼륨·네트워크 |
| tests/markdown-html-block.test.js | HTML sanitizer 단위 회귀 테스트 |
| tests/content-in-article-ad.test.js | 공개 본문 인아티클 광고 삽입 위치 계산 단위 회귀 테스트 |
| tests/content-gallery-images.test.js | 공개 본문 라이트박스 이미지 목록과 갤러리 행 분할 단위 회귀 테스트 |
| tests/content-image-urls.test.js | 공개 본문 이미지 파생 URL·srcset·갤러리 sizes 단위 회귀 테스트 |
| tests/markdown-block-context.test.js | 관리자 블록 설정 패널의 활성 블록 컨텍스트 단위 회귀 테스트 |
| tests/markdown-editor-history.test.js | 관리자 Markdown 에디터 undo/redo 히스토리 항목과 선택 범위 보정 단위 회귀 테스트 |
| tests/markdown-editor-keyboard.test.js | 관리자 Markdown 에디터 전역 단축키 판별 단위 회귀 테스트 |
| tests/markdown-editor-media.test.js | 관리자 Markdown 에디터 미디어 선택 helper의 종류·선택 가능 여부·미리보기·선택 상태·블록 생성 단위 회귀 테스트 |
| tests/markdown-slash-commands.test.js | 관리자 슬래시 명령 파싱·미디어 action·모달 종류·제외 줄 Set 갱신·하이라이트 인덱스 보정·방향키 순환·키보드 동작 분류·포커스 대상·textarea 선택 위치·원문 줄 교체 삽입 단위 회귀 테스트 |
| tests/markdown-slash-menu-scroll.test.js | 관리자 슬래시 메뉴 선택 항목 scrollTop 보정 단위 테스트 |
| tests/useAdminMarkdownSlashMenu.test.js | 관리자 Markdown 에디터 슬래시 메뉴 composable 상태 관리 단위 테스트 |
| tests/useAdminMarkdownHistory.test.js | 관리자 Markdown 에디터 히스토리 composable의 기록·undo/redo·그룹화·보관 개수 단위 테스트 |
| tests/useContentMarkdownBlocks.test.js | 공개 Markdown 블록 계산 composable의 파싱·제목 ID·광고 삽입·하단 삽입 줄 단위 테스트 |
| tests/useContentMarkdownLightbox.test.js | 공개 Markdown 라이트박스 composable의 열기·좌우 순환·ESC 닫기·키보드 이벤트 해제 단위 테스트 |
| tests/useContentMarkdownImageDrag.test.js | 공개 Markdown 라이브 이미지·갤러리 드래그 composable의 병합·삽입·분리·정렬 단위 테스트 |
| tests/useContentMarkdownLiveSelection.test.js | 공개 Markdown 라이브 선택 composable의 포커스 요청·예약 포커스 초기화·line focus/blur 단위 테스트 |
| tests/useContentMarkdownFencedBlocks.test.js | 공개 Markdown fenced 블록 composable의 코드·콜아웃·토글 아래 문단 삽입 단위 테스트 |
| tests/useContentMarkdownParagraphs.test.js | 공개 Markdown 문단 composable의 커밋·분리·인용/코드/콜아웃 단축 변환 단위 테스트 |
| tests/useContentMarkdownLists.test.js | 공개 Markdown 목록 composable의 번호 유지·항목 커밋·Enter 분기 단위 테스트 |
| tests/useContentMarkdownQuotes.test.js | 공개 Markdown 인용 composable의 옵션 줄 보존·접두 정리·아래 이탈·문단 복귀 단위 테스트 |
| tests/markdown-block-parser.test.js | 공개 Markdown 본문 블록 파싱 단위 회귀 테스트 |
| tests/markdown-fenced-meta.test.js | Markdown fenced 블록 시작·종료 줄 탐색, 본문 수집, 메타 파싱 단위 회귀 테스트 |
| tests/markdown-quote.test.js | Markdown 인용 옵션 파싱과 편집 줄 변환 단위 회귀 테스트 |
| tests/multipart-file-upload.test.js | multipart 스트리밍·제한 단위 회귀 테스트 |
| tests/csp-report.test.js | CSP URL 최소화·payload 형식 단위 회귀 테스트 |
| tests/media-catalog.test.js | 미디어 URL·역할·참조·LIKE 이스케이프 단위 회귀 테스트 |
| tests/markdown-table.test.js | Markdown 표 행·정렬·블록 파싱 단위 회귀 테스트 |
| tests/admin-pagination.test.js | 관리자 페이지네이션 페이지 보정·ellipsis 항목 단위 테스트 |
| tests/playwright/api/core-api.spec.js | 인증·부분 설정 저장·공개 목록·CSP·미디어 reconcile/fallback·세션 무효화 API 통합 10건 |
| tests/playwright/e2e/admin-guard-and-settings.spec.js | 설정 카드 독립 저장과 미저장 이탈 취소 브라우저 E2E 2건 |
| tests/playwright/e2e/admin-publish.spec.js | 관리자 로그인·게시물 발행·공개 화면 확인 브라우저 E2E 1건 |
| tests/playwright/e2e/admin-regressions.spec.js | 태그 추천 연속 선택·미디어 파생 탭 배지 숨김·단일 이미지 `{size=}` 너비 브라우저 회귀 테스트 |
## DB 마이그레이션
| 파일 | 용도 |
|------|------|
| db/migrations/056_site_settings_post_tag_limit.sql | 사이트 설정의 게시물 태그 최대 개수 컬럼 추가 |
| db/migrations/057_navigation_recommended_favicon_cache.sql | 추천 사이트 파비콘 캐시 URL·갱신 시각 컬럼 추가 |
| db/migrations/058_tag_header_cover.sql | 태그 헤더 이미지·오버레이 제목·본문 컬럼 추가 |
| db/migrations/059_post_analytics_traffic_daily.sql | 게시물별 유입원·디바이스·키워드 일별 축약 집계 테이블 추가 |
| db/migrations/060_page_listing_metadata.sql | 페이지 홈 진열장 노출 메타 컬럼 추가 |
| db/migrations/061_page_listing_sections.sql | 페이지 홈 진열장 섹션 관리 테이블 추가 |
| db/migrations/062_site_settings_display_counts.sql | 사이트 설정 공개 목록 표시개수 컬럼 추가 |
| db/migrations/063_site_settings_upload_limits.sql | 사이트 설정 관리자 업로드 제한 컬럼 추가 |
| db/migrations/064_posts_admin_pinned.sql | 관리자 글 목록 전용 상단 고정 컬럼·정렬 인덱스 추가 |
| db/migrations/065_public_search_index.sql | 공개 통합 검색용 `search_text` 컬럼·자동 갱신 트리거·`pg_trgm` GIN 인덱스 추가 |
| db/migrations/066_analytics_active_session_ip.sql | 실시간 접속 세션 IP 표시용 `analytics_active_sessions.ip_address` 컬럼 추가 |
| db/migrations/067_users_session_version.sql | 비밀번호 변경 후 기존 로그인 세션 무효화용 `users.session_version` 컬럼 추가 |
| db/migrations/068_csp_violation_aggregates.sql | CSP 정책 버전·문서 경로·지시어·차단 origin·브라우저 계열 위반 집계 테이블 추가 |
| db/migrations/069_media_catalog.sql | `media_metadata` 파일 카탈로그 필드·상태·관계, `media_references`, `media_catalog_state` 추가 |
## 서버 미들웨어
| 파일 | 용도 |
|------|------|
| server/middleware/admin-api-session.js | `/admin/api/*` 요청마다 관리자 세션과 현재 DB 권한(`owner`/`admin`) 재확인 |
| server/middleware/html-page-renderer.js | HTML 문서 모드 고정 페이지(`/pages/:slug`)를 Nuxt 렌더링 대신 `text/html` 원문으로 응답 |
| server/middleware/security-headers.js | 전역 보안 헤더 적용, `/pages/**` 강제 CSP 제외 결정 |
| server/utils/security-headers.js | 최소 강제 CSP와 사용자 코드·광고 호환 Report-Only·Reporting API 헤더 구성 |
| server/utils/csp-report-request-limit.js | CSP 보고 IP 해시 기준 분당 60회·버킷 상한 제한 |
| server/utils/upload-root.js | 일반 `public/uploads`와 Playwright 전용 임시 업로드 루트 분리 |
| server/routes/uploads/[...path].get.js | 런타임 업로드 파일 제공 API(`/app/public/uploads` 볼륨 파일을 `/uploads/**`로 스트리밍, 원본 장기 캐시·파생 이미지 재검증 캐시·조건부 요청 304 지원) |
| server/routes/sitemap.xml.get.js | 공개 sitemap XML(`/sitemap.xml`) |
| server/routes/robots.txt.get.js | 공개 robots.txt(`/robots.txt`, sitemap 위치 안내) |
| server/routes/rss.xml.get.js | 공개 RSS 2.0 피드(`/rss.xml`) |
| server/routes/feed.xml.get.js | 공개 RSS 2.0 피드 별칭(`/feed.xml`) |
| server/routes/rss.get.js | 공개 RSS 2.0 피드 별칭(`/rss`) |
| server/plugins/site-custom-code.js | 공개 Nuxt HTML 응답에 사이트 설정 헤더·푸터 코드 삽입(`/admin`, `/api`, `/uploads`, `/_nuxt`, `/ads.txt` 제외) |
| server/utils/post-thumbnail-image.js | 게시물 업로드 이미지의 카드 썸네일·Pages 3:4 커버 썸네일·본문 표시용 1600px/720px WebP·라이트박스용 2560px WebP 이미지 URL·디스크 경로·생성 가능 여부·본문 이미지 추출 규칙 |
| server/utils/media-library.js | 관리자 미디어 파일 스캔·폴더 메타·사용처 계산·삭제/이름 변경, 30초 전체 목록 공유 캐시·동시 요청 단일 실행·파일 변경 시 무효화, 미디어 참조 전용 게시물·페이지 조회 기반 원본/파생 이미지 사용처 연결 |
| server/utils/sitemap.js | 공개 sitemap XML·robots.txt 생성 |
| server/utils/rss-feed.js | 공개 발행글 기반 RSS 2.0 XML 생성, 게시물 이미지 Media RSS 썸네일 출력 |
## 서버 저장소
| 파일 | 용도 |
|------|------|
| server/repositories/csp-report-repository.js | 민감 원문 없이 정규화된 CSP 위반 차원을 PostgreSQL에 누적 집계 |
| server/repositories/media-catalog-repository.js | 미디어 파일·참조 dual-write, DB SQL 목록, 준비 상태 검사, 파일 비파괴 reconcile·missing 표시 |
| server/repositories/content-repository.js | 게시물·페이지·태그·사이트 설정 저장 후 미디어 참조 최선 노력 동기화 |
## 사이트 컴포넌트
| 파일 | 화면 위치 |
|------|-----------|
| components/auth/AuthPasswordVisibilityToggle.vue | 로그인·회원가입 비밀번호 표시/숨김 토글(SVG, scoped 스타일·`field-name`으로 접근성 레이블 구분) |
| components/site/SiteTopChrome.vue | 공개 레이아웃 상단 고정 영역(어나운스 바+헤더), `--site-top-chrome-height` CSS 변수 |
| components/site/SiteAnnouncementBar.vue | 공개 사이트 상단 어나운스 배너(문구·선택 링크·hex 배경색·텍스트 정렬·닫기) |
| components/site/SiteHeader.vue | 모든 공개 페이지 상단, 사이트 이름 텍스트 브랜드, `grid-cols-3`로 검색 패널 중앙 정렬(`md+`), 우측 사용자 아바타 드롭다운(아바타 없거나 비로그인 시 사람 아이콘), `/`·`SiteSearchModal` |
| components/site/SiteSearchModal.vue | `Teleport`·전체 화면 딤·Tags/Posts 결과·일치 구간 강조, 열림 시 `html.site-search-open` 스크롤 잠금, IME 조합 중 표시값 디바운스 반영·조합 종료 후 최종 검색어 즉시 반영과 공백·Unicode 정규화 |
| components/site/LeftSidebar.vue | 왼쪽 사이드바, `lg+`는 `sticky`+상단 크롬 CSS 변수 기준 높이+내부 무스크롤바 스크롤, `lg` 미만은 같은 CSS 변수 아래의 고정 슬라이드 패널, 상단 메뉴는 `SidebarPrimaryNavList`+`provide`로 트리·펼침 상태(`sori-primary-nav-expanded`), 태그 Categories 아래 공개 `GET /api/navigation`의 `recommended` 카드 목록(수동 썸네일 > 서버 캐시 파비콘 > 외부 프록시 fallback), Authors 영역은 비공개, 푸터 `footer` 링크는 `flex-wrap`·테마 버튼 `shrink-0`, 태그 카테고리·테마 점은 `site-sidebar-nav-row` 호버 |
| components/site/SidebarPrimaryNavList.vue | 상단 네비: 부모·리프 동일 `before` 막대/호버 원형, 내부 현재 경로 `--site-accent`, 행 `w-full`+`site-sidebar-nav-row` 호버(`#F7F4EF` 라이트), `inject`·`localStorage` 펼침 |
| components/site/RightSidebar.vue | 오른쪽 사이드바, 일반 화면은 설정 기반 사이트 로고 48px 정사각형 고정·SNS Follow(프리셋·사용자 SVG, 16px 아이콘 중앙 정렬)·오른쪽 사이드 광고를 표시, 게시글 상세 데스크톱은 블로그 소개·Follow 대신 최상단 H1~H3 TOC와 TOC 아래 게시물 사이드 광고(모바일 숨김, 스크롤 위치 기반 활성 표시·내부 자동 스크롤, 세로 기준선), About 영역은 비공개, `lg+` 스티키 top·높이는 상단 크롬 CSS 변수를 사용하며 데스크톱 외곽 구분선은 레이아웃 오른쪽 컬럼이 담당 |
| components/site/SiteAdSlot.vue | 사이트 설정 Ads HTML 코드 렌더링, 메인 피드·메인 인피드·오른쪽 사이드·게시물 오른쪽 사이드·게시물 본문 상단·인아티클·하단 광고 슬롯 |
| components/site/MainColumn.vue | 메인 화면 중앙, `lg:max-w-[720px]`로 본문 상한 |
| components/site/HomeHero.vue | 홈 상단 720px 커버 배너, 라이트·다크 테마별 이미지 교체, 왼쪽 하단 오버레이 제목·본문 |
| components/site/PostCard.vue | 목록의 게시물 카드, 카드 hover 인터랙션, 태그는 있을 때만 색상 배지 메타에 표시하고 태그 페이지 링크 제공, 오른쪽 아래 게시물 링크 화살표 |
| components/site/PostCardMedia.vue | 게시물 카드 썸네일(`featuredImageThumbnail` 우선, 없으면 대표 이미지 원본 사용. 대표 이미지 없으면 모바일 3줄·`sm` 이상 4줄 제목 placeholder 표시, 이미지 유무와 관계없이 썸네일 영역 크기 고정) |
| components/site/SitePagination.vue | 공개 목록 공용 번호형 페이지네이션, 이전·다음 화살표와 첫/끝/현재 주변 페이지 직접 이동, 현재 페이지 브랜드 포인트 강조, 많은 페이지의 `...` 접기, 모바일 가로 스크롤 |
| components/site/TagHeader.vue | 태그 페이지 헤더 |
| components/comments/PostComments.vue | 게시물 상세 `#comments` 영역, 회원 댓글/답글(1단) 작성 및 목록 표시, slug 변경 시 입력·답글·오류·좋아요 상태 초기화와 지연 응답 폐기, 기본 정렬 최신순(최신순·인기순·오래된순 선택), 입력값 기반 등록 버튼 활성화, 작성자 썸네일/좋아요/상대시간 표시 |
## 관리자 컴포넌트
| 파일 | 화면 위치 |
|------|-----------|
| components/admin/AdminSettingsNavIcon.vue | 사이트 설정 좌측 내비 항목 아이콘(`iconId`별 SVG: 브랜드·사이트 정보·POST·사이트 코드·Ads·SNS·게시물보내기·가져오기 등·미구현 placeholder) |
| components/admin/AdminSiteCodeSettingsCard.vue | 관리자 사이트 설정의 ads.txt·공통 헤더 코드·공통 푸터 코드 카드 |
| components/admin/AdminAdsSettingsCard.vue | 관리자 사이트 설정의 위치별 Ads 코드 카드(메인 피드·메인 인피드·오른쪽 사이드·게시물 오른쪽 사이드·게시물 본문 상단·인아티클·하단) |
| components/admin/AdminPostExportFileRow.vue | 관리자 사이트 설정 내보내기 작업의 분할 파일 선택 행 |
| components/admin/AdminMediaFolderPanel.vue | 관리자 미디어 화면의 폴더 사이드바(라이브러리 폴더 트리·폴더별 개수·드래그 드롭 이동·폴더 삭제 메뉴·폴더 추가 버튼·시스템 이미지 탭 안내 패널) |
| components/admin/AdminMediaGrid.vue | 관리자 미디어 화면의 그리드 카드 목록(미디어 선택 체크·이미지/영상/파일 썸네일·사용처 개수·상태 배지·드래그 시작·상세 열기 이벤트) |
| components/admin/AdminMediaDetailModal.vue | 관리자 미디어 화면의 상세 모달(미리보기·파일 정보·썸네일 상태·폴더·사용 현황·파일명·삭제 액션 표시) |
| components/admin/AdminMediaVideoThumbnail.vue | 관리자 미디어 목록 비디오 항목의 초반 프레임 캔버스 썸네일 |
| components/admin/AdminPostForm.vue | 관리자 글 작성/수정 폼, Ghost형 툴바(왼쪽 상태 텍스트·Publish/Update/Unpublish/Unschedule, 서버 반영 상태 기준 분기), 초안만 서버 디바운스 자동 저장·자동 저장 실패 payload 반복 재시도 차단·자동 저장 실패/진행 중 이탈 차단·신규 임시 슬러그·중복 슬러그 필드 하단 오류 표시·중복 슬러그 중 Publish/Update/최종 저장 비활성화·저장 중 추가 변경 재자동저장·발행 저장 중 이탈 확인·발행·예약·멤버십·비공개 상태 저장, 미저장 비교에서 태그 표시명 보조값 제외, 공개 상태 전환 시 빈 발행 시각 현재 시각 보정, 발행 모달(중앙 배치), 설정 패널 상태와 이벤트 연결, 미리보기 emit·미저장 이탈 가드, 자동 생성 썸네일을 숨기는 원본 전용 대표 이미지 선택(서버 페이지네이션·파일명/사용처 검색·번호형 페이지 이동·작은 파생 이미지 우선 미리보기·고정 높이 모달), 대표 이미지 본문 상단 표시 토글, 추천 글 토글, 사이트 설정 기준 태그 최대 개수 제한, 태그 색상 배지 다중 입력·최근 사용 태그 5개 우선 추천·메인 태그 드롭다운·부분 검색 추천, 새 태그 입력명 유지와 `/`→`-` 슬러그 변환 |
| components/admin/AdminMarkdownMediaPickerModal.vue | 관리자 Markdown 에디터 미디어 선택 모달 UI(업로드·라이브러리 탭, 검색 입력, 미디어 그리드, 업로드 영역, 페이지네이션, 적용/취소 버튼) |
| components/admin/AdminMarkdownModeToggle.vue | 관리자 Markdown 에디터 작성/미리보기 모드 전환 버튼 UI |
| components/admin/AdminMarkdownPreviewSurface.vue | 관리자 Markdown 에디터 라이브 미리보기 표면 UI(ContentMarkdownRenderer 연결, 라이브 편집 포커스·선택 메서드와 DOM 참조 노출) |
| components/admin/AdminMarkdownSlashMenu.vue | 관리자 Markdown 에디터 슬래시 명령 메뉴 UI(명령 아이콘·라벨·슬러그 표시, 키보드 하이라이트 상태 표시, 루트 DOM 노출) |
| components/admin/AdminMarkdownUploadingBadge.vue | 관리자 Markdown 에디터 소스 작성 표면의 업로드 중 상태 배지 |
| components/admin/AdminMarkdownWriteSurface.vue | 관리자 Markdown 에디터 소스 작성 표면 UI(textarea, 라인 번호 gutter, 업로드 상태 배지, DOM 참조 노출) |
| components/admin/AdminPostSettingsSidebar.vue | 관리자 게시물 작성/수정 우측 설정 사이드바(Post URL·상태·발행 시각·요약·태그·대표 이미지 표시·추천 글·검색엔진 노출·본문 통계·삭제 버튼·블록 설정 패널 오버레이) |
| components/admin/AdminPageForm.vue | 관리자 페이지 작성/수정 폼, 게시글 작성과 같은 전체 화면 에디터·상단 저장 툴바·접이식 오른쪽 설정 패널, 저장 payload 기준 미저장 비교·라우트/브라우저 이탈 확인, 페이지 공개 상태 선택, HTML 문서 기본 모드, 홈 Pages 진열장 노출 메타와 등록된 페이지 섹션 검색형 선택, 빈 본문/`!`+Tab HTML 골격 자동 완성, 항상 보이는 일반 텍스트/HTML 모드 선택, 한글 제목 영문 슬러그 자동 변환, HTML textarea 커서 위치 파일 URL 삽입, HTML 태그 내부 스마트 따옴표 정규화 |
| components/admin/AdminMarkdownEditor.vue | 관리자 글 Markdown-first 에디터, 라이브·소스 모드 `/` 슬래시 명령(`/표` 기본 표 템플릿 포함)·미디어 모달(이미지·갤러리·비디오·오디오·파일, 업로드 탭 기본·첫 순서, 업로드 완료 파일 자동 선택, 라이브러리 탭은 `/admin/api/media?paged=1` 서버 페이지 응답·파일명/사용처 제목 검색·번호형 페이지 이동, 카드·본문·라이트박스·Pages 커버 자동 생성 이미지 숨김, 원본 URL 선택 유지·갤러리 선택 순서 배지·목록 미리보기는 720px 본문 파생 이미지 또는 카드 썸네일 우선, 검색 결과 수와 무관한 고정 높이 패널, 업로드 중 중복 업로드·닫기 차단·로딩 표시), 코드 블록 본문 슬래시 명령 비활성화, 커서 블록 컨텍스트·선택 텍스트 색상 컨텍스트 `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 블록 현재 닫는 줄 기준 교체, 블록 패널 바깥 클릭·지원 블록 밖 커서 이동 시 닫기·미디어 모달 중 유지, 인용 마지막 줄 아래 방향키 외부 문단 포커스 이동, 인용·콜아웃·코드·토글 선언 줄 옵션 수정, 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 등록·변경·삭제, 기본 정보·레이블·관리자 노트·활동 요약, 설정 메뉴의 비밀번호 변경·멤버 삭제 모달, 저장 토스트, 미저장 변경사항 이탈 확인) |
| components/admin/AdminUnsavedChangesModal.vue | 관리자 편집 화면 공통 미저장 변경사항 이탈 확인 모달(상단 40px 위치) |
| components/admin/AdminConfirmModal.vue | 관리자 공통 확인 모달(제목·본문 슬롯·확인/취소 버튼, primary/danger 톤) |
| components/admin/AdminModalFrame.vue | 관리자 공통 일반 모달 프레임(오버레이, dialog 접근성 속성, 기본 패널 스타일, 바깥 클릭 닫기) |
| components/admin/AdminPopoverSurface.vue | 관리자 공통 팝오버 표면(border·shadow·radius 기반 스타일, 동적 태그·role·인라인 위치 스타일 전달) |
| components/admin/AdminToast.vue | 관리자 공통 우측 상단 토스트 표시(성공·오류·안내 톤, 화면별 상단 위치 조정) |
| components/admin/AdminSearchInput.vue | 관리자 공통 검색 입력(돋보기 아이콘, IME 검색 이벤트 전달, 외부 focus/select 노출) |
| components/admin/AdminSelectInput.vue | 관리자 공통 select 입력(문자·숫자 옵션 값, 기본 필터·정렬 옵션, chevron 아이콘, `v-model` 전달) |
| components/admin/AdminFilterPillGroup.vue | 관리자 공통 pill 필터 그룹(선택 상태·개수 배지·aria-pressed) |
| components/admin/AdminPagination.vue | 관리자 공통 번호형 페이지네이션(이전·다음 화살표, 첫/끝/현재 주변 페이지, ellipsis 접기) |
| components/admin/AdminAnalyticsTrendChart.vue | 관리자 통계 추이 막대 차트(축 라벨·증감 툴팁·기간 페이지 이동) |
| lib/analytics-chart-ui.js | 통계 차트 라벨·페이지네이션·증감 계산 유틸 |
## 관리자 컴포저블
| 파일 | 화면 위치 |
|------|-----------|
| composables/useAdminUnsavedChangesGuard.js | 관리자 게시글/멤버 편집 화면 라우트 이탈 확인과 브라우저 `beforeunload` 연결 |
## 콘텐츠 컴포넌트
| 파일 | 화면 위치 |
|------|-----------|
| components/content/ContentRenderer.vue | 게시물/페이지 본문 |
| components/content/ContentMarkdownRenderer.vue | 마크다운 문자열 기반 본문 렌더링, 문단 text-base(16px), 빈 줄 spacer 보존·hard break `<br>` 처리, 표준 마크다운 표 파싱·렌더링(셀 내부 인라인 링크와 `<br>` 줄바꿈 포함), 공개 게시물 인아티클 광고를 본문 길이에 따라 0~2회 삽입, Obsidian식 위첨자·아래첨자 인라인 렌더링, 확장 블록 파싱, `:::` fenced 블록 원본 범위 보정, 닫히지 않은 코드 펜스 하위 콘텐츠 보호, 인용 막대 색상 옵션(`> [!bg=...]`), 라이브 문단 `>` 즉시 인용 변환과 ` ``` `·`!!!` Enter 코드 블록·콜아웃 단축 생성, 라이브 콜아웃·인용 포커스 기반 오른쪽 설정 패널 연결, 라이브 인용·콜아웃 인라인 색상·굵게·링크 렌더링, 라이브 인용·콜아웃·토글 기본 목록 렌더링과 멀티라인 편집 줄 범위 포커스, 인용 `>. ` 접두 커밋 정리, 위/아래 방향키 외부 문단 이탈, 인용 Backspace 문단 복귀, 라이브 방향키 이동 시 편집 가능한 줄·카드형 블록 탐색, 라이브 코드·콜아웃·토글 내부 줄 삭제와 마지막 줄 블록 삭제, 라이브 토글 저장 기본 펼침·닫힘 상태 반영, 공개 콜아웃·토글 내부 본문 블록 렌더링, 라이브 이미지·갤러리 드래그 상태 연결, 본문 표시용 720w/1600w WebP `srcset` 캐시 버전 우선 표시와 원본 fallback, 단일 이미지 `{size=숫자}` 최대 너비 표시, 단일 이미지·갤러리 통합 라이트박스의 2560px WebP 캐시 버전 우선 표시, 갤러리 비율 기반 행 레이아웃, 라이브 이미지·갤러리 hover 삭제 액션, 리스트 마커 파란 계열 통일과 여러 줄 항목 첫 줄 기준 정렬 |
| components/content/ContentMarkdownEditableInline.vue | 라이브 모드 공통 인라인 편집 영역, 일반 인라인 마크다운·Obsidian식 첨자 렌더링과 멀티라인 인라인 마크다운 렌더링, `blockMarkdown` 옵션 기반 기본 불릿/번호 목록 표시와 공개 목록 마커 색상 적용, plain text 멀티라인 본문·끝 줄바꿈 보존, 한글 IME 조합 확정 Enter의 블록별 동작 연결, 위/아래 인접 블록 이동 시 편집 스크롤 추적, Shift 위/아래 인접 블록 선택 확장·단계적 `Cmd/Ctrl+A` 처리, 멀티라인 Enter 텍스트 값 치환, 첫 줄 빈 줄 포함 줄바꿈 유지 |
| components/content/ContentMarkdownInlineSegments.vue | 공개·라이브 본문 공통 인라인 세그먼트 렌더링(링크·굵게·기울임·인라인 코드·첨자·인라인 색상), 링크·굵게·기울임·색상 내부 중첩 인라인 렌더링, 사용자 화면 fragment 주석 반복을 줄이는 단일 루트 구조 |
| components/content/ContentMarkdownBlockGroup.vue | Markdown 본문 블록 단위 렌더 그룹, 라이브 삽입 영역을 조건부로만 DOM에 추가해 공개 화면 fragment 주석 감소 |
| lib/markdown-live-selection.js | 라이브 모드 Selection Bridge, 인접 contenteditable 범위 확장·블록/문서 전체 선택·교차 선택 삭제 마크다운 반영, 콜아웃·인용 전체 선택 삭제 시 빈 본문 줄 보존, Selection focus 기준 연속 확장 |
| components/content/ProseHeading.vue | h1~h6 제목, 기본 mt-12 제거 |
| components/content/ProseImage.vue | 본문 내 이미지, 클릭 확대 요청, 본문 표시용 이미지 실패 시 원본 fallback, lazy 로딩, 로드 실패·빈 URL placeholder |
| components/content/ProseList.vue | 목록 |
| components/content/ProseBlockquote.vue | 인용구, 왼쪽 세로 막대형 기본 스타일과 색상 프리셋, 다크모드 기본 인용 텍스트 가독성 보정 |
| components/content/ProseCodeBlock.vue | 코드 블록 공통 셸(다크 배경, 선택 줄번호 gutter, 공개 복사 버튼) |
| components/content/ContentMarkdownCodeBlockEditor.vue | 라이브 모드 코드 블록 인라인 편집(Language·줄번호 토글) |
| components/content/ProseButton.vue | 버튼 |
| components/content/ContentMarkdownCalloutEditor.vue | 라이브 모드 콜아웃 멀티라인 본문 편집, 본문 인라인 굵게·링크·색상·기본 목록 렌더링, 제목·아이콘 표시 여부·배경 반영, 내부 여러 줄 범위 선택 |
| components/content/ProseCallout.vue | Callout 카드(Emoji 표시/숨김, 선택 제목, 인용과 같은 배경 프리셋, 헤더 아래 본문 줄바꿈) |
| components/content/ProseToggle.vue | Toggle 카드(펼침 애니메이션, chevron·제목 클릭 트리거) |
| components/content/ContentMarkdownToggleEditor.vue | 라이브 모드 토글 제목·본문 인라인 편집, 본문 인라인·기본 목록 렌더링, 저장된 기본 펼침·닫힘 상태 초기 반영 |
| components/content/ProseVideo.vue | `:::video` 공개 비디오 카드 |
| components/content/ProseAudio.vue | `:::audio` 공개 오디오 플레이어 카드 |
| components/content/ProseFile.vue | `:::file` 공개 다운로드 파일 카드, 제목·파일명이 같으면 용량 중심 보조 정보 표시 |
| components/content/ProseProduct.vue | 상품 카드 |
| components/content/ProseBookmark.vue | 본문 북마크 카드(썸네일·도메인·`http(s)` 외부 링크) |
| components/content/ProseSignup.vue | 본문 회원가입·뉴스레터 CTA 카드 |
| components/content/ProseHeaderCard.vue | 헤더 카드 |
| components/content/ProseEmbed.vue | 상단 외부 여백 없이 하단 여백만 두는 YouTube 영상 iframe, X/Twitter 소셜 iframe, Mastodon `/embed` iframe, 제한된 사용자 iframe HTML, 기타 `http(s)` 외부 링크 |
| components/content/ProseHtml.vue | `:::html` 본문 HTML 렌더링, 표 기본 스타일과 허용 목록 sanitizer 적용, 서버 전용 `sanitize-html`과 브라우저 DOM sanitizer 분리 |
## 관리자 페이지
| 파일 | 화면 |
|------|------|
| pages/admin/index.vue | 대시보드(상단 요약: 현재 접속자·오늘 방문자·누적 방문자·게시물 수, 일일·주간·월간·년간 선택형 방문자수·평균 체류·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 반영·이탈 직전 플러시, 저장 토스트 |
| pages/admin/posts/[id].vue | 글 수정, `AdminPostForm`, 저장·초안 디바운스 자동 저장(`autoSaving`)·이탈 직전 플러시·삭제·토스트 |
| pages/admin/posts/[id]/analytics.vue | 게시물별 통계, 누적 조회수·기간별 조회/방문자 차트·유입/디바이스/키워드·읽음/체류/스크롤 지표 |
| pages/admin/posts/preview.vue | 글 미리보기(공개 상세와 동일한 중앙 컬럼·수평 패딩) |
| pages/admin/pages/index.vue | 페이지 목록, 게시글 목록과 같은 상단 검색·상태 필터·노출 필터·정렬·새 페이지 버튼 구조, 전체·홈 표시·추천·필터 표시 개수 요약, 추천 별·페이지 커버 썸네일 열, 제목·슬러그·요약·상태·섹션 기준 검색, 제목 아래 주소·공개 보기 hover 아이콘, 홈 표시·섹션·추천 배지, 조회수·통계 모달, 상태 표시, 화면 기준 행 more vert 메뉴(수정·삭제) |
| pages/admin/pages/new.vue | 전체 화면 페이지 작성, HTML 문서 기본 모드 저장, 홈 Pages 진열장 노출 메타, 저장 토스트 |
| pages/admin/pages/[id].vue | 전체 화면 페이지 수정, HTML 문서/일반 텍스트 모드 저장, 홈 Pages 진열장 노출 메타, 설정 패널 삭제, 저장/삭제 토스트 |
| pages/admin/media/index.vue | 미디어 관리, **미디어 라이브러리/대표 이미지/본문 이미지/프로필 이미지** 탭, 글·멤버 목록과 같은 검색창, 파일 직접 추가, 라이브러리 파일 종류 필터와 미사용 토글, 시스템 탭 전체/미사용 배지형 필터, 목록 카드 오른쪽 위 사용 개수 배지, `/admin/api/media?paged=1` 기반 50·100·200개 단위 페이지네이션과 현재 페이지 선택·선택 삭제, 표시 개수 셀렉트 SVG chevron 화살표, 이미지·비디오·오디오·파일 종류 필터, 원본 fallback·대표 이미지·본문 이미지 역할 배지(파생 파일 자체와 파생 탭에서는 숨김), 그리드용 작은 파생 이미지 우선 표시와 원본 fallback, 대표 이미지 원본 파생 파일 생성·재생성, 본문 이미지 생성·재생성, 비디오 프레임 썸네일, 폴더 트리 more vert(폴더 삭제), 검색·드래그·상세 모달 등 |
| pages/admin/navigation/index.vue | 메뉴 관리: 메인 네비게이션/페이지 섹션/하단 네비게이션/추천 사이트 탭, 각 탭 작업줄 왼쪽 추가·오른쪽 저장 버튼, 메인·하단 메뉴 추가 모달, 페이지 섹션 추가 모달·수정·삭제·섹션 드래그 정렬·섹션별 카드형 페이지 순서 변경 모달(추천 우선 표시·섹션에서 제거 포함), 추천 사이트는 공개와 같은 카드 목록+편집 모달(전체 URL·썸네일·파비콘 갱신), 행 more vert(삭제), 저장 대상별 버튼(`네비게이션 저장`/`페이지 섹션 저장`), `useAdminToast` |
| components/admin/AdminRowMoreMenu.vue | 관리자 행 more vert 메뉴(트리거·화면 기준 팝오버) |
| composables/useAdminRowMenu.js | 관리자 행 메뉴 열림 상태·바깥 클릭 닫기 |
| pages/admin/tags/index.vue | 태그 관리(메인 태그 드래그 정렬 자동 저장·more vert 메뉴, 일반 태그 배지 more vert 메뉴·검색/정렬, 태그 추가 버튼), 액션 피드백 토스트 |
| pages/admin/tags/new.vue | 태그 생성 |
| pages/admin/tags/[id].vue | 태그 수정 |
| pages/admin/settings/index.vue | 사이트 설정 Ghost형 전체 화면, 카드별 필드만 PATCH하고 성공 필드만 폼에 반영하는 독립 저장, 단순 설정 섹션 공통 저장 헬퍼, 설정 내비게이션 상태 연결, **블로그 제목·설명** 편집 상태·저장 요청·스냅샷 복원 연결, **사이트 정보** 편집 상태·저장 요청·로고 업로드 처리 연결, **SNS 정보** 편집 상태·저장 요청 연결, **POST 설정** 편집 상태·저장 요청·스냅샷 복원 연결, **메인 화면** 편집 상태·저장 요청·커버 업로드 처리 연결, **브랜드** 컬러 정규화·편집 상태·저장 요청 연결, **어나운스 바** 편집 상태·저장 요청 연결, **스팸 필터** 편집 상태·저장 요청·값 정규화 연결, **사이트 용량** 데이터 조회·새로고침 이벤트 연결, **게시물 내보내기** 요청 body 생성·작업 등록·목록 갱신·작업 액션 연결, **게시물 가져오기** 파일 검증·작업 생성 요청·작업 센터 모달 연결, 진행 중 요청 버튼 잠금 |
| components/admin/AdminSettingsNavigation.vue | 관리자 설정 좌측 내비게이션(설정 검색 입력·검색 결과 목록·모바일 구역 선택·구역 이동 이벤트) |
| components/admin/AdminHomeCoverSettingsCard.vue | 관리자 설정 메인 화면 카드(라이트·다크 커버 미리보기·드롭존·파일 선택·오버레이 문구·저장 이벤트) |
| components/admin/AdminBrandSettingsCard.vue | 관리자 설정 브랜드 컬러 카드(읽기 미리보기·색상 입력·텍스트 입력·예시 배지·저장 이벤트) |
| components/admin/AdminTitleDescriptionSettingsCard.vue | 관리자 설정 블로그 제목·설명 카드(읽기 행·편집 입력·공개 화면 미리보기·저장 이벤트) |
| components/admin/AdminSiteInfoSettingsCard.vue | 관리자 설정 사이트 정보 카드(로고 미리보기·로고 파일 선택·사이트 URL·저작권 문구·저장 이벤트) |
| components/admin/AdminSocialSettingsCard.vue | 관리자 설정 SNS 정보 카드(링크 읽기 배지·아이콘 프리셋·주소·사용자 SVG·저장 이벤트) |
| components/admin/AdminAnnouncementSettingsCard.vue | 관리자 설정 어나운스 바 카드(사용 토글·문구·링크·배경색·정렬·저장 이벤트) |
| components/admin/AdminPostSettingsCard.vue | 관리자 설정 POST 설정 카드(수정일 표시·태그 최대 개수·공개 목록 표시개수·업로드 제한·저장 이벤트) |
| components/admin/AdminBackupSummaryCard.vue | 관리자 설정 사이트 용량 카드(콘텐츠 수량·미디어 용량·자동 생성 이미지·내보내기 파일·큰 파일·새로고침 이벤트) |
| components/admin/AdminPostExportJobList.vue | 관리자 설정 최근 내보내기 작업 목록 카드(상태·진행도·실패 상세·파일 선택·선택 다운로드 이벤트) |
| components/admin/AdminPostExportRequestCard.vue | 관리자 설정 게시물 내보내기 요청 카드(범위·연도·월·직접 날짜·분할 옵션·요청 이벤트) |
| components/admin/AdminPostImportCard.vue | 관리자 설정 게시물 가져오기 카드(ZIP input·드롭존·작업 센터 버튼·적용 이벤트) |
| components/admin/AdminPostImportJobModal.vue | 게시물 Import 작업 센터 모달(전체 진행률·게시물별 대기/진행중/완료/스킵/오류·완료 삭제 이벤트) |
| components/admin/AdminSpamSettingsCard.vue | 관리자 설정 스팸 필터 카드(가입 금지 닉네임 읽기·편집 textarea·저장 이벤트) |
| lib/signup-blocked-usernames.js | 가입 금지 닉네임 정리·매칭·안내 문구 |
| pages/admin/members/index.vue | 관리자 멤버 목록(Ghost형 테이블, 글 목록과 같은 테두리형 검색, 조건 필터, 멤버 추가 버튼, 닉네임+이메일, 등급+비활성 상태, 가입일+최근 활동, IP, 댓글 수) |
| pages/admin/members/new.vue | 관리자 멤버 추가(썸네일 URL, 이름, 이메일, 레이블, 관리자 노트) |
| pages/admin/members/[id].vue | 관리자 멤버 상세/수정(회원 요약, 읽기 전용 진입 후 수정하기 전환, 변경 시 저장 버튼 활성, 저장 버튼 기반 멤버 등급 변경, 권한 변경 불가 상황 셀렉트 잠금/텍스트 표시, 가입 정보, 활동 요약, 기본 정보 저장, 삭제 후 목록 이동) |
## 공개 페이지
| 파일 | 화면 |
|------|------|
| pages/index.vue | 홈, `site_settings` 커버가 있을 때만 라이트·다크 이미지 지원 `HomeHero`, Featured/Latest, 사이트 설정 표시개수 기준 Latest·Featured·Pages 데이터 제한, 홈 표시 페이지를 섹션별 도서 진열장형 Pages 선반으로 노출, Pages 추천 카드는 왼쪽 위 SVG 아이콘 배지 표시, Featured와 Pages 선반의 독립 이전·다음 버튼 및 문서 레벨 포인터 추적 기반 드래그 슬라이드·스냅(이동 임계값 미만 클릭은 링크 이동, 포인터 캡처는 드래그 확정 뒤 적용), Pages 선반 ResizeObserver 기반 버튼 상태 갱신, Pages 카드 hover 상단 여백 보정, Latest 피드 Compact 기본값·List·Cards 보기, Compact 모바일 썸네일 80px 정사각형·Compact/List 설명 2줄 제한, Latest 메타는 태그가 있을 때만 링크 배지 표시, 카드 오른쪽 아래 화살표는 게시물 상세 링크, Featured는 추천 글이 있을 때만 표시하며 이미지 없는 추천 글은 제목 placeholder 썸네일과 모바일 터치 가로 스크롤·스냅, 끝에서 화살표 비활성 |
| pages/posts/index.vue | 게시물 전체 목록, 사이트 설정 Posts 표시개수 기준 서버 페이지네이션, 공용 번호형 페이지네이션, 태그는 있을 때만 카드 메타에 링크로 표시 |
| pages/posts/[slug].vue | `/post/:slug` 리다이렉트 |
| pages/post/[slug].vue | 블로그 글 상세, 본문 블로킹 조회 후 완성 화면 진입, 첫 태그가 있을 때만 메타 행에 태그 링크, H1~H3 본문 제목을 오른쪽 TOC 상태로 제공, 공개 회원 로그인 세션의 회원이 글쓴이(`author_id`)이면 공유 버튼 옆 새 탭 편집 링크 표시, 게시물 SEO/OG 메타 출력(요약 없으면 본문 fallback), 공유 모달(X/Bluesky/Facebook/LinkedIn/Email/링크복사), 회원 댓글 섹션 |
| pages/tags/index.vue | 태그 전체 목록, 중앙 히어로와 3열 태그 카드, 좌측 컬러 보더/hover 오버레이 |
| pages/tags/[slug].vue | `/tag/:slug` 리다이렉트 |
| pages/tag/[slug].vue | 태그별 글 목록, 존재하지 않는 태그 404, 사이트 설정 태그 게시물 표시개수 기준 서버 태그 필터·공용 번호형 페이지네이션, 태그 헤더 이미지가 있으면 상단 이미지 헤더 표시, 없으면 기본 태그명·설명 + 공통 섹션 패딩을 쓰는 리스트형 게시물 카드, 카드 태그 배지와 오른쪽 아래 화살표 링크 |
| pages/pages/[slug].vue | 고정 페이지 상세, HTML 문서 모드는 직접 진입 시 서버 미들웨어 원문 응답·클라이언트 내부 이동 시 현재 URL reload로 서버 원문 응답 재진입 |
| pages/signup.vue | 회원가입 3단계, `emailOtpConfigured`일 때 이메일 OTP·인증번호 받기, 모바일 OTP 입력창 높이 보정, `POST /api/auth/email-otp/request` |
| pages/signin.vue | 로그인, `/forgot-password` 링크 |
| pages/forgot-password.vue | 비밀번호 찾기(Resend 설정 시 OTP 발송·`POST /api/auth/password-reset/confirm`) |
| pages/settings/index.vue | 회원 설정(상단 프로필 요약, 가입 정보, 댓글 참여도, 하단 프로필 입력·이전 로그인 활동, 썸네일 변경·제거, 닉네임 저장, 설정 메뉴 모달 비밀번호 변경·회원 탈퇴) |
## 서버 API
| 파일 | 기능 |
|------|------|
| server/api/posts.get.js | 공개 게시물 목록 API(`published`, VIP 이상 등급 시 `members`, 기본 개수 상한, 본문 제외 요약 응답, `limit`·`tag`·`featured`·`paginated` 조회 옵션) |
| server/api/posts/[slug].get.js | 공개 게시물 상세 API(`published`, VIP 이상 등급 시 `members`) |
| server/api/pages.get.js | 공개 고정 페이지 목록 API(`published`만, `listed=1`·섹션별 `limit` 조회 옵션) |
| server/api/pages/[slug].get.js | 공개 고정 페이지 상세 API(`published`만) |
| server/api/tags.get.js | 공개 태그 목록 API, 기본 메인 태그 반환·`tagType=all` 전체 태그 메타 반환 |
| server/routes/admin/api/tags/cover.post.js | 관리자 태그 헤더 이미지 업로드 API(`/uploads/system/tag-cover-*.webp`) |
| server/api/search.get.js | 통합 검색 API(`q` 쿼리, 게시물·페이지 `search_text` 인덱스 기반) |
| server/api/site-settings.get.js | 공개 사이트 설정 API |
| server/api/homepage-widget.get.js | gethomepage customapi용 당일·7일·30일·180일·365일·누적·콘텐츠 통계 위젯 API |
| server/api/csp-report.post.js | 32KB·JSON 계열 형식·IP 해시 빈도 제한과 민감 URL 최소화를 적용한 CSP 위반 204 수집 API |
| server/repositories/blog-statistics-repository.js | 공개 게시글·댓글·페이지·태그·회원·누적 방문 통계 집계 |
| server/routes/admin/api/posts/[id]/featured.put.js | 관리자 글 목록 추천 상태 전용 수정 API |
| server/api/navigation.get.js | 공개 네비게이션 API |
| server/api/auth/signup.post.js | 회원 가입 API(선택 `emailOtp`, Resend 설정 시 일반 가입에 필수) |
| server/api/auth/bootstrap-status.get.js | 최초 관리자 여부 + `emailOtpConfigured` |
| server/api/auth/email-otp/request.post.js | Resend로 OTP 발송(`signup` / `password_reset`), 발송 실패 챌린지 삭제 |
| server/api/auth/password-reset/confirm.post.js | OTP 검증 후 비밀번호 재설정 |
| server/repositories/email-otp-repository.js | `email_otp_challenges` CRUD·검증 |
| server/utils/email-otp.js | OTP 생성·해시 |
| server/utils/resend-mail.js | Resend REST 발송 |
| server/api/auth/login.post.js | 계정·IP 실패 횟수 제한을 적용한 회원 로그인 API |
| server/api/auth/me.get.js | 회원 세션 조회 API(`isAdmin`, `role` 포함) |
| server/api/auth/logout.post.js | 회원 로그아웃 API |
| server/api/auth/profile.get.js | 회원 프로필 조회 API |
| server/api/auth/profile.put.js | 회원 프로필 수정 API(닉네임·`avatarUrl`; 관리 썸네일 URL 교체 시 메타만 분리) |
| server/api/auth/avatar.post.js | 회원 썸네일 업로드 API(WebP 변환, 최소 해상도 검증, 중앙 1:1 강제 크롭, 품질 보정, `media_metadata` 논리 폴더 `썸네일`) |
| server/api/auth/avatar.delete.js | 회원 썸네일 삭제 API |
| server/api/auth/check-username.get.js | 닉네임 중복 확인 API |
| server/api/auth/password.put.js | 회원 비밀번호 변경 API |
| server/api/auth/account.delete.js | 회원 탈퇴 API(마지막 `owner` 보호, 관리자 세션 함께 정리) |
| server/api/posts/[slug]/comments.get.js | 게시물 댓글 목록 조회 API, 회원 등급 기반 멤버십 본문 접근 확인 |
| server/api/posts/[slug]/comments.post.js | 게시물 댓글 작성 API, 일반/멤버십 본문 접근 정책 적용 |
| server/api/posts/[slug]/comments/[commentId]/like.post.js | 댓글 좋아요 토글 API, 일반/멤버십 본문 접근 정책 적용 |
| server/routes/admin/api/auth/login.post.js | 계정·IP 실패 횟수 제한을 적용한 관리자 로그인 API |
| server/routes/admin/api/auth/logout.post.js | 관리자 로그아웃 API |
| server/routes/admin/api/auth/me.get.js | 관리자 세션 조회 API |
| server/routes/admin/api/posts.get.js | 관리자 게시물 목록 API, 기본 배열 응답과 `paged=true` 페이지 응답 지원 |
| server/routes/admin/api/posts.post.js | 관리자 게시물 생성 API |
| server/routes/admin/api/posts/[id].get.js | 관리자 게시물 상세 API |
| server/routes/admin/api/posts/[id]/references.get.js | 관리자 게시물 링크 참조 목록 API |
| server/routes/admin/api/posts/[id].put.js | 관리자 게시물 수정 API |
| server/routes/admin/api/posts/[id].delete.js | 관리자 게시물 삭제 API |
| server/routes/admin/api/posts/export-jobs.get.js | 관리자 게시물 Export 작업 목록 API |
| server/routes/admin/api/posts/export-jobs.post.js | 관리자 게시물 Export 작업 요청 API |
| server/routes/admin/api/posts/export-jobs/[jobId].delete.js | 관리자 게시물 Export 작업·생성 ZIP 삭제 API |
| server/routes/admin/api/posts/export-jobs/[jobId]/retry.post.js | 관리자 게시물 Export 실패 작업 재시도 API |
| server/routes/admin/api/posts/export-jobs/[fileId]/download.get.js | 관리자 게시물 Export 분할 ZIP 다운로드 API |
| server/routes/admin/api/posts/import.post.js | 관리자 게시물 Export ZIP Import 작업 생성 API |
| server/routes/admin/api/posts/import-jobs.get.js | 관리자 게시물 Import 작업 목록 조회·대기 작업 실행 예약 API |
| server/routes/admin/api/posts/import-jobs/[jobId].delete.js | 관리자 게시물 Import 완료·실패 작업 삭제 API |
| server/routes/admin/api/pages.get.js | 관리자 고정 페이지 목록 API(홈 표시·섹션·추천 메타 포함) |
| server/routes/admin/api/pages.post.js | 관리자 고정 페이지 생성 API |
| server/routes/admin/api/pages/[id].get.js | 관리자 고정 페이지 상세 API |
| server/routes/admin/api/pages/[id].put.js | 관리자 고정 페이지 수정 API |
| server/routes/admin/api/pages/[id].delete.js | 관리자 고정 페이지 삭제 API |
| server/routes/admin/api/page-sections.get.js | 관리자 페이지 섹션 목록 API |
| server/routes/admin/api/page-sections.post.js | 관리자 페이지 섹션 생성 API |
| server/routes/admin/api/page-sections/[id].put.js | 관리자 페이지 섹션 이름 수정 API |
| server/routes/admin/api/page-sections/[id].delete.js | 관리자 페이지 섹션 삭제 API |
| server/routes/admin/api/page-sections/reorder.put.js | 관리자 페이지 섹션 순서 저장 API |
| server/routes/admin/api/page-sections/[id]/pages/reorder.put.js | 관리자 페이지 섹션 내부 페이지 순서 저장 API |
| server/routes/admin/api/media.get.js | 관리자 미디어 목록 API. 기본 요청은 기존 호환용 전체 배열, `paged=1` 요청은 탭·폴더·종류·미사용·검색 필터와 페이지 메타가 포함된 미디어 관리 화면용 응답 |
| server/routes/admin/api/media.put.js | 관리자 미디어 파일명 변경 및 단일/복수 폴더 변경 API |
| server/routes/admin/api/media.delete.js | 관리자 미디어 삭제 API |
| server/routes/admin/api/media/thumbnail.post.js | 원본 이미지의 게시물 목록 카드·본문 표시·Pages 커버 썸네일 생성·재생성 API |
| server/routes/admin/api/media/reconcile.post.js | 파일을 변경하지 않고 카탈로그 upsert·참조 백필·누락 파일 `missing` 표시를 수행하는 관리자 수동 API |
| server/routes/admin/api/media-folders.get.js | 관리자 미디어 폴더 목록 API |
| server/routes/admin/api/media-folders.post.js | 관리자 미디어 폴더 생성 API |
| server/routes/admin/api/uploads.post.js | 관리자 게시물·페이지용 다중 미디어 원본 업로드 API(임시 디스크 스트리밍, 수신 중 파일 수·종류별/전체 용량 제한, Unicode 원본명 기반 hard link 배타 이동·충돌 시 넘버링, 실패 파일 정리, `/uploads/posts` 저장, 성공 시 `media_metadata`를 `미분류`로 기록) |
| server/routes/admin/api/member-avatar.post.js | 관리자 새 회원 생성 전 썸네일 사전 업로드 API(`/uploads/members/avatars` 저장, WebP 변환·1:1 크롭) |
| server/routes/admin/api/tags.get.js | 관리자 태그 목록 API(`tagType`, `q`, `limit` 검색 옵션) |
| server/routes/admin/api/tags.post.js | 관리자 태그 생성 API |
| server/routes/admin/api/tags/[id].get.js | 관리자 태그 상세 API |
| server/routes/admin/api/tags/[id].put.js | 관리자 태그 수정 API |
| server/routes/admin/api/tags/[id].delete.js | 관리자 태그 삭제 API |
| server/routes/admin/api/tags/reorder.put.js | 관리자 메인 태그 순서 일괄 저장 API |
| server/routes/admin/api/settings.get.js | 관리자 사이트 설정 조회 API |
| server/routes/admin/api/settings.patch.js | 관리자 사이트 설정 허용 필드 검증·부분 수정 API |
| server/routes/admin/api/settings/backup-summary.get.js | 관리자 사이트 용량 API(콘텐츠 수량 DB 집계, `public/uploads` 파일 용량 스캔) |
| server/routes/admin/api/settings.put.js | 관리자 사이트 설정 수정 API |
| server/routes/admin/api/settings/logo.post.js | 관리자 사이트 로고 업로드 API(`/uploads/system/logo-YYYYMM-*.webp`, `/uploads/system/favicon-YYYYMM-*.png` 생성, `시스템` 미디어 메타 저장, DB 반영 없이 URL 반환) |
| server/routes/admin/api/settings/home-cover.post.js | 관리자 메인 화면 커버 업로드 API(`/uploads/system/home-cover-YYYYMM-*.webp` 생성, `시스템` 미디어 메타 저장, 라이트·다크 슬롯용 URL 반환) |
| server/routes/ads.txt.get.js | 사이트 설정 ads.txt 루트 text/plain 응답 |
| server/routes/admin/api/navigation.get.js | 관리자 네비게이션 목록 API |
| server/routes/admin/api/navigation.put.js | 관리자 네비게이션 일괄 저장 API(추천 사이트 파비콘 캐시 보존, 캐시 없는 추천 사이트 백그라운드 최초 갱신) |
| server/routes/admin/api/navigation/[id]/favicon-refresh.post.js | 추천 사이트 파비콘 수동 갱신 API |
| server/utils/recommended-site-favicon.js | 추천 사이트 파비콘 fetch·`/uploads/system/recommended-favicon-*.png` 저장·일괄 갱신 |
| server/plugins/recommended-favicon-cron.js | 매월 1일 03:00(KST) 추천 사이트 파비콘 자동 갱신 |
| server/plugins/post-export-worker.js | 서버 시작·30초 주기 게시물 Export 대기/중단 작업 복구 실행 |
| scripts/refresh-recommended-favicons.js | 추천 사이트 파비콘 수동 일괄 갱신 CLI(`npm run navigation:refresh-recommended-favicons`) |
| server/routes/admin/api/members.get.js | 관리자 멤버 목록 API |
| server/routes/admin/api/members.post.js | 관리자 멤버 생성 API |
| server/routes/admin/api/members/[id].get.js | 관리자 멤버 상세 API |
| server/routes/admin/api/members/[id].put.js | 관리자 멤버 기본 정보 수정 API(회원 전용 썸네일 교체·제거 시 메타 연결 분리) |
| server/routes/admin/api/members/[id]/avatar.post.js | 관리자 멤버 썸네일 업로드 및 즉시 반영 API |
| server/routes/admin/api/members/[id]/role.put.js | 관리자 멤버 권한 변경 API(`owner`/`admin`/`vip`/`member`, 관리자 상호 조작 차단, 마지막 소유자 보호) |
| server/routes/admin/api/members/[id]/ownership-transfer.post.js | 소유자 권한 이전 API(대상→소유자, 요청자→관리자) |
| server/utils/content-schema.js | Zod 콘텐츠 스키마 |
| server/utils/sample-content.js | 샘플 콘텐츠 저장소 |
| server/utils/admin-auth.js | DB 세션 버전을 포함한 관리자 세션 쿠키 인증 유틸리티 |
| server/utils/analytics-admin-exclusion.js | 관리자 세션 요청의 공개 통계 수집 제외 판별 |
| server/utils/member-auth.js | DB 세션 버전 검증을 포함한 회원 세션 쿠키 인증 유틸리티 |
| server/utils/login-attempt-limit.js | 회원·관리자 로그인 계정·IP별 15분 실패 횟수 제한 유틸리티 |
| server/utils/request-ip.js | 프록시 헤더 포함 요청 IP 조회 유틸리티 |
| server/utils/member-avatar.js | 회원 전용 썸네일 경로 검증·프로필 분리 시 `media_metadata`만 제거(디스크는 관리자 미디어에서 정리) |
| server/utils/member-avatar-upload.js | 회원 썸네일 공통 업로드 검증·Unicode 원본명 기반 파일명·WebP 변환·중앙 1:1 크롭·저장 유틸 |
| server/utils/admin-post-input.js | 관리자 게시물 입력값 Zod 검증 스키마, 자동 생성 이미지 URL의 대표 이미지 지정 차단, 공개 상태의 빈 발행 시각 현재 시각 보정 |
| server/utils/admin-page-input.js | 관리자 고정 페이지 입력값 검증 스키마 |
| server/utils/admin-site-settings-input.js | 관리자 사이트 설정 입력값 검증 스키마 |
| server/utils/admin-navigation-input.js | 관리자 네비게이션 입력값 검증 스키마 |
| server/utils/admin-tag-input.js | 관리자 태그 입력값 검증 스키마 |
| server/utils/site-settings.js | 사이트 설정 기본값 유틸리티 |
| server/utils/navigation-items.js | DB 없을 때 기본 네비 항목(UUID id·parentId·isFolder) |
| server/utils/navigation-tree.js | 네비 검증·삽입 순서·공개 primary 트리·DFS sort_order 재부여 |
| server/utils/media-library.js | 업로드 미디어·Unicode 파일명 정리·논리 폴더(`미분류`, 예약 `썸네일`)·`avatarOwner` 부착·아바타 삭제/이름변경 차단·게시물 카드·본문·Pages 커버 썸네일 사용처 연결 |
| server/repositories/postgres-client.js | PostgreSQL 클라이언트 |
| server/repositories/content-repository.js | 콘텐츠 조회 저장소 |
| server/repositories/post-export-repository.js | 게시물 Export 작업·분할 파일 계획·원본 자산 store 방식 스트리밍 ZIP 생성, PostgreSQL advisory lock 기반 다중 인스턴스 단일 worker 저장소 |
| server/repositories/post-import-repository.js | 게시물 Export ZIP Import 저장소(frontmatter 제한 읽기·자산 엔트리 스트리밍·URL 재매핑·게시물 생성·Import job/item 상태 관리·작업 재개) |
| server/plugins/post-import-worker.js | 대기·중단된 게시물 Import 작업을 주기적으로 백그라운드 실행 |
| server/repositories/member-repository.js | 회원 조회/생성 저장소 |
| server/repositories/comment-repository.js | 댓글 조회/생성/좋아요 저장소, 공개·멤버십 게시물 접근 조건 통합 |
| server/repositories/analytics-repository.js | 방문·게시물·페이지·유입 통계 집계·관리자 요약/날짜 상세 조회·방문자 해시 보관 정리 |
| server/utils/analytics-pageview-input.js | `POST /api/analytics/pageview` 검증·관리자 세션 제외·IP 해시 분당 상한·기록 |
| server/utils/adsense-report.js | AdSense OAuth access token 발급·보고서 조회·대시보드 요약 생성 |
| server/utils/zip-writer.js | `archiver` 기반 게시물 Export ZIP 디스크 스트리밍 생성 유틸리티 |
| server/utils/zip-reader.js | `unzipper` 기반 게시물 Import ZIP 중앙 디렉터리·엔트리 제한 검증 및 스트림 유틸리티 |
| db/migrations/070_post_import_jobs.sql | 게시물 Import 작업·게시물별 상태 테이블 |
| server/utils/multipart-file-upload.js | `busboy` 기반 단일·다중 multipart 파일 수·개별/전체 용량 제한과 임시 디스크 스트리밍 유틸리티 |
| server/api/analytics/pageview.post.js | 공개 통계 수집 API |
| server/api/analytics/heartbeat.post.js | 공개 heartbeat·체류·스크롤 수집 API |
| server/utils/analytics-heartbeat-input.js | heartbeat 검증·관리자 세션 제외·IP 해시 분당 상한·기록 |
| server/utils/analytics-request-limit.js | 공개 통계 pageview·heartbeat 인메모리 IP 해시 윈도 제한 |
| server/routes/admin/api/analytics/summary.get.js | 관리자 통계 요약 API |
| server/routes/admin/api/analytics/posts.get.js | 관리자 인기 게시물 API |
| server/routes/admin/api/analytics/posts/[id].get.js | 관리자 게시물별 통계 API |
| server/routes/admin/api/analytics/pages/[id].get.js | 관리자 페이지별 통계 API |
| server/routes/admin/api/analytics/pages.get.js | 관리자 인기 페이지 API |
| 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/adsense/summary.get.js | 관리자 대시보드 AdSense 예상 수익·페이지뷰·노출·클릭 요약 API |
| plugins/site-analytics.client.js | 공개 라우트 pageview·heartbeat·read 클라이언트 전송 |
| plugins/bfcache-page-restore.client.js | 뒤로가기 캐시(bfcache) 복원 시 라우터 경로와 실제 URL 어긋남을 감지해 새로고침(HTML 문서 모드 페이지 이동 후 뒤로가기 잔상 방지) |
| plugins/navigation-lock.client.js | 페이지 이동 중 `html.site-navigating` 클래스로 링크·버튼 클릭을 잠가 중복 클릭 차단(안전 타임아웃 포함) |
## 데이터베이스
| 파일 | 기능 |
|------|------|
| db/migrations/001_initial_schema.sql | PostgreSQL 초기 테이블 스키마 |
| db/migrations/002_seed_development.sql | 개발용 샘플 데이터 |
| db/migrations/003_add_tag_display_fields.sql | 태그 표시 순서와 색상 필드 추가 |
| db/migrations/004_add_site_settings.sql | 사이트 설정 테이블 추가 |
| db/migrations/024_navigation_recommended_location.sql | `navigation_items.location`에 `recommended` 값 허용 |
| db/migrations/017_navigation_hierarchy.sql | `navigation_items`에 `parent_id`·`is_folder`, `(location,label,url)` 유니크 제거 |
| db/migrations/019_dedupe_navigation_items.sql | 반복 마이그레이션으로 생긴 네비게이션 중복 행 정리 및 중복 방지 인덱스 |
| db/migrations/005_add_navigation_items.sql | 네비게이션 항목 테이블 추가 |
| db/migrations/006_add_media_metadata.sql | 미디어 메타데이터 테이블 추가 |
| db/migrations/007_add_media_folders.sql | 미디어 폴더 테이블 추가 |
| db/migrations/016_media_category_normalize.sql | `media_metadata` 레거시 `posts`→`미분류`, `회원/썸네일`→`썸네일` 정리 |
| db/migrations/008_add_post_seo_fields.sql | 게시물 SEO 필드 추가 |
| db/migrations/009_add_post_og_image.sql | 게시물 OG 이미지 필드 추가 |
| db/migrations/010_add_members_and_comments.sql | 회원/댓글 테이블 추가 |
| db/migrations/011_add_member_profile_and_activity.sql | 회원 아바타/최근 활동 컬럼 추가 및 닉네임 유니크 인덱스 추가 |
| db/migrations/012_add_comment_likes.sql | 댓글 좋아요 테이블 추가 |
| db/migrations/014_add_user_role_levels.sql | 회원 권한 단계(owner/admin/member) 컬럼 추가 |
| db/migrations/013_add_user_admin_role.sql | 회원 관리자 권한 컬럼 추가 및 첫 사용자 관리자 승격 |
| db/migrations/015_add_tag_type_and_reorder_support.sql | 태그 유형(`managed`/`general`) 컬럼 추가 |
| db/migrations/030_analytics_daily_stats.sql | 사이트·게시물 일별 통계·일별 방문자 해시 테이블 |
| db/migrations/031_analytics_engagement_and_realtime.sql | 체류·스크롤 집계 컬럼·실시간 접속 세션 테이블 |
| db/migrations/032_add_post_author.sql | 게시물 작성자(`posts.author_id`) 컬럼 추가 및 기존 글 owner/admin backfill |
| db/migrations/033_site_settings_home_cover_dark_image.sql | 사이트 설정 다크모드 홈 커버 이미지 URL 컬럼 추가 |
| db/migrations/034_add_page_render_mode.sql | 고정 페이지 렌더링 모드 컬럼 추가 |
| db/migrations/035_default_pages_to_html_document.sql | 고정 페이지 렌더링 모드 기본값을 HTML 문서로 변경 |
| db/migrations/036_content_visibility_statuses.sql | 게시물 상태에 `members`/`private`, 페이지 상태에 `published`/`draft`/`private` 제약 추가 |
| db/migrations/037_add_vip_member_role.sql | 회원 권한 단계에 `vip` 허용 |
| db/migrations/038_restore_owner_when_missing.sql | 소유자가 없는 경우 기존 관리자 중 가장 오래된 계정을 소유자로 복구 |
| db/migrations/039_page_analytics_and_navigation_recommended_metadata.sql | 페이지 통계 테이블·추천 사이트 대체 텍스트/썸네일 컬럼 추가 |
| db/migrations/040_post_export_jobs.sql | 게시물 Export 작업·분할 파일 계획 테이블 추가 |
| db/migrations/041_post_export_progress.sql | 게시물 Export 작업 진행도 컬럼 추가 |
| db/migrations/042_post_export_date_range.sql | 게시물 Export 날짜 범위 컬럼 추가 |
| db/migrations/043_post_export_size_and_error_detail.sql | 게시물 Export 목표 용량·실패 상세 로그 컬럼 추가 |
| db/migrations/044_site_settings_custom_code.sql | 사이트 설정 ads.txt·공통 헤더 코드·공통 푸터 코드 컬럼 추가 |
| db/migrations/045_analytics_traffic_sources.sql | 방문자 유입원·디바이스·키워드 일별 집계 테이블 추가 |
| db/migrations/054_add_post_show_featured_image.sql | 게시물 상세 제목 아래 대표 이미지 표시 여부 컬럼 추가 |
| db/migrations/055_add_post_tag_sort_order.sql | 게시물별 태그 표시 순서(`post_tags.sort_order`) 추가 |
| db/migrations/059_post_analytics_traffic_daily.sql | 게시물별 유입원·디바이스·키워드 일별 축약 집계 테이블 추가 |
## 설정/배포
| 파일 | 기능 |
|------|------|
| package.json | Nuxt 실행·문법 검사·Node 회귀 테스트·전체 verify 스크립트와 의존성 |
| nuxt.config.js | Nuxt 앱 설정, `tailwindcss.cssPath`로 `main.css` 단일 엔트리, Tailwind 모듈, 관리자 QA를 위한 개발 도구 비활성화, 회원 썸네일 최소/최대 해상도·품질 런타임 설정 |
| tailwind.config.js | Tailwind 테마 설정 |
| assets/css/main.css | 전역 스타일, 공개 배경·사이드바 배경 통일 기준, 관리자 라이트 테마 격리(`admin-layout`), 좌측 사이드바/그리드 전환 애니메이션, 네비게이션 세로 바 hover 효과, 게시물 카드 제목 공통 인터랙션(`post-title-link`), 이동 중 클릭 잠금(`site-navigating`) |
| composables/useMenuState.js | 좌측 메뉴 열림 상태·`closeMenu`(모바일 백드롭 등), 모바일은 마운트 시 항상 닫힘 시작·`menuMounted`로 첫 페인트 슬라이드 플래시 방지 |
| composables/useThemeMode.js | 사용자 화면 라이트/다크 테마 상태 관리 |
| middleware/admin-auth.global.js | 관리자 페이지 접근 인증 |
| middleware/pages-html-document.global.js | HTML 문서 모드 고정 페이지(`/pages/:slug`) 클라이언트 소프트 이동을 전체 페이지 이동으로 전환(뒤로가기 잔상 방지) |
| scripts/dev-server.js | 로컬 개발 서버 링크 요약 출력 |
| scripts/migrate-database.js | 로컬·NAS DB 마이그레이션 적용/상태/baseline, 파일 실행+이력 기록 단일 트랜잭션 |
| scripts/migrate-development-db.js | 기존 로컬 개발 DB 마이그레이션 명령 호환 래퍼 |
| scripts/migrate-production-db.sh | npm 없는 NAS 호스트용 운영 DB 마이그레이션 적용/상태/baseline 실행 |
| .env.example | 환경 변수 예시 |
| Dockerfile | NAS 운영 이미지 빌드, `.output/server` 기반 앱 런타임과 이미지 백필 스크립트 포함 |
| tests/markdown-html-block.test.js | 게시물 HTML sanitizer 공격 우회·허용 HTML 회귀 테스트 |
| tests/multipart-file-upload.test.js | 다중 multipart 디스크 스트리밍·파일 크기 제한 회귀 테스트 |
| docker-compose.yml | NAS 컨테이너 실행 초안, PostgreSQL 호스트 기본 loopback 바인딩 |