이 프로젝트는 백엔드 개발자 김대성의 개인 블로그입니다. Astro 프레임워크를 기반으로 구축된 정적 사이트 생성(SSG) 블로그로, 블로그 포스트, 프로젝트 포트폴리오, 이력서를 관리합니다.
배포 URL: https://www.dskim.dev
배포 플랫폼: Vercel
- Framework: Astro 5.16.6
- Content Format: MDX (Markdown + JSX)
- Image Optimization: Sharp 0.34.3
- Language: TypeScript
- Content Collections: 타입 안전한 컨텐츠 관리 (Blog, Project, Resume)
- RSS Feed:
@astrojs/rss를 통한 RSS 피드 생성 - Sitemap:
@astrojs/sitemap을 통한 자동 사이트맵 생성 - Image Optimization: Sharp를 통한 이미지 최적화
- PDF 생성: Puppeteer (이력서 PDF 생성용)
- 파일 감시: Chokidar
- 병렬 실행: Concurrently
DS_Blog/
├── src/
│ ├── assets/ # 이미지, 폰트 등 정적 자산
│ │ ├── projects/ # 프로젝트 이미지
│ │ └── resume/ # 이력서 이미지
│ ├── components/ # 재사용 가능한 Astro 컴포넌트
│ │ ├── BaseHead.astro # 메타데이터, SEO 설정
│ │ ├── Header.astro # 네비게이션 헤더
│ │ ├── Footer.astro # 푸터
│ │ ├── FormattedDate.astro # 날짜 포맷팅
│ │ └── HeaderLink.astro # 헤더 링크 컴포넌트
│ ├── content/ # MDX 컨텐츠 파일
│ │ ├── blog/ # 블로그 포스트 (YYYYMMDDHHMM.mdx 형식)
│ │ ├── project/ # 프로젝트 포트폴리오
│ │ └── resume/ # 이력서
│ ├── layouts/ # 페이지 레이아웃
│ │ └── BlogPost.astro # 블로그/프로젝트 포스트 레이아웃
│ ├── pages/ # 라우팅 페이지
│ │ ├── index.astro # 홈페이지
│ │ ├── blog/
│ │ │ ├── index.astro # 블로그 목록 페이지
│ │ │ └── [...slug].astro # 블로그 포스트 동적 라우팅
│ │ ├── project/
│ │ │ ├── index.astro # 프로젝트 목록 페이지
│ │ │ └── [...slug].astro # 프로젝트 상세 동적 라우팅
│ │ ├── resume.astro # 이력서 페이지
│ │ ├── 404.astro # 404 에러 페이지
│ │ └── rss.xml.js # RSS 피드 생성
│ ├── styles/
│ │ └── global.css # 전역 스타일 (다크 모드)
│ ├── consts.ts # 사이트 상수 (SITE_TITLE, SITE_DESCRIPTION)
│ └── content.config.ts # Content Collections 스키마 정의
├── public/ # 정적 파일 (빌드 시 그대로 복사)
│ ├── favicon.svg
│ ├── fonts/ # 웹폰트
│ ├── og.png # Open Graph 이미지
│ └── robots.txt
├── scripts/
│ └── generate-resume-pdf.js # 이력서 PDF 생성 스크립트
├── astro.config.mjs # Astro 설정 파일
├── package.json
└── tsconfig.json
MDX 파일 작성 (src/content/blog/*.mdx)
↓
Content Collections 스키마 검증 (src/content.config.ts)
↓
getCollection()으로 컨텐츠 로드
↓
동적 라우팅 (pages/blog/[...slug].astro)
↓
BlogPost 레이아웃으로 렌더링 (layouts/BlogPost.astro)
↓
정적 HTML 생성 (빌드 시)
src/content.config.ts: 컨텐츠 스키마 정의 → 모든 컨텐츠 파일의 frontmatter 검증src/pages/blog/[...slug].astro:getCollection('blog')로 컨텐츠 로드 →BlogPost레이아웃 사용src/layouts/BlogPost.astro: 블로그와 프로젝트 모두에서 공통 사용src/components/BaseHead.astro: 모든 페이지에서 메타데이터 제공src/consts.ts: 사이트 전역 상수 (제목, 설명)
이 파일은 Content Collections의 스키마를 정의합니다. Zod를 사용하여 타입 안전성을 보장합니다.
주요 컬렉션:
- blog: 블로그 포스트
- 필수:
title,description,pubDate - 선택:
updatedDate,heroImage,tags
- 필수:
- project: 프로젝트 포트폴리오
- 추가 필드:
startDate,endDate,thumbnail,gitHub,gitLab,link,teamSize등
- 추가 필드:
- resume: 이력서
- 최소한의 스키마 (title, description은 선택)
파일 경로 패턴:
- Blog:
src/content/blog/YYYYMMDDHHMM.mdx(예:202601060145.mdx) - Project:
src/content/project/PROJECT_NAME.mdx(예:PICA.mdx)
주요 기능:
- 모든 블로그 포스트를 날짜순으로 정렬하여 표시
- 첫 번째 포스트를 "Featured Post"로 강조 표시
- 클라이언트 사이드 검색 기능 (제목, 내용, 태그 검색)
- 페이지네이션 (페이지당 10개 포스트)
- URL 쿼리 파라미터로 검색어와 페이지 번호 유지
검색 로직:
- MDX 파일을 직접 읽어 본문 내용 추출
- 마크다운 문법 제거 후 검색 인덱스 생성
- 클라이언트 사이드에서 실시간 필터링
동작 방식:
getCollection('blog')로 모든 블로그 포스트 로드getStaticPaths()에서 각 포스트의id를slug로 매핑render()함수로 MDX를 HTML로 변환BlogPost레이아웃으로 감싸서 렌더링
URL 구조: /blog/202601060145/ (파일명이 slug가 됨)
사용처: 블로그 포스트와 프로젝트 포스트 모두에서 사용
주요 기능:
- Hero 이미지 표시 (있는 경우)
- 제목, 날짜, 태그 표시
- 프로젝트인 경우: GitHub/GitLab 링크, 팀 크기 등 추가 정보 표시
- MDX 컨텐츠를
<slot />으로 렌더링
조건부 렌더링:
isProject변수로 블로그/프로젝트 구분- 프로젝트인 경우에만 링크 버튼 표시
특징:
- 프로젝트를 지정된 순서로 정렬:
['PICA', 'GOLDEN_TICKET', 'TODO', 'MERGE', 'FOX_BOOK_FINDER'] thumbnail이미지가 있으면 우선 사용, 없으면heroImage사용- 프로젝트 기간 (
startDate~endDate) 표시
기능:
getCollection('blog')로 모든 블로그 포스트 로드@astrojs/rss를 사용하여 RSS XML 생성- 각 포스트의 frontmatter 데이터를 RSS 아이템으로 변환
접근 경로: /rss.xml
주요 설정:
- Site URL:
https://www.dskim.dev - Integrations:
@astrojs/mdx: MDX 지원@astrojs/sitemap: 자동 사이트맵 생성
- Image Service: Sharp 사용
limitInputPixels: 268402689(기본값의 약 4배) - 큰 이미지 처리용
기능:
- SEO 메타 태그 (title, description)
- Open Graph 태그 (소셜 미디어 공유용)
- Twitter Card 태그
- Canonical URL
- RSS 피드 링크
- 폰트 프리로드
이미지 처리:
imageprop이 있으면 해당 이미지를 OG 이미지로 사용- 없으면
public/og.png를 기본값으로 사용
디자인 시스템:
- 다크 모드 전용: 밝은 텍스트, 어두운 배경
- 색상 팔레트:
- Accent:
#4f8cff(파란색) - 텍스트: 밝은 회색 계열
- 배경:
#050814(어두운 파란색)
- Accent:
- 네온 글로우 효과: 카드 호버 시 네온 효과
- 폰트: Atkinson (웹폰트)
파일 위치: src/content/blog/YYYYMMDDHHMM.mdx
Frontmatter 형식:
---
title: "포스트 제목"
pubDate: 2026-01-06T01:45+09:00
description: "포스트 설명"
updatedDate: 2026-01-07T10:00+09:00 # 선택
heroImage: ../../assets/blog/image.webp # 선택
tags: ["태그1", "태그2"] # 선택
---
## 본문 내용
마크다운 형식으로 작성파일명 규칙: YYYYMMDDHHMM.mdx (예: 202601060145.mdx)
파일 위치: src/content/project/PROJECT_NAME.mdx
Frontmatter 형식:
---
title: "프로젝트 이름"
description: "프로젝트 설명"
pubDate: 2026-01-01T00:00+09:00
startDate: 2025-01-01T00:00+09:00 # 선택
endDate: 2025-12-31T23:59+09:00 # 선택
thumbnail: ../../assets/projects/PROJECT/thumbnail.webp # 선택
heroImage: ../../assets/projects/PROJECT/hero.webp # 선택
tags: ["기술1", "기술2"] # 선택
gitHub: "https://github.com/user/repo" # 선택
gitHubPrivate: true # 선택 (비공개 저장소인 경우)
gitLab: "https://gitlab.com/user/repo" # 선택
link: "https://project-url.com" # 선택
linkClosed: false # 선택 (서비스 종료 여부)
teamSize: "3명" # 선택
---
## 프로젝트 상세 내용# 의존성 설치
npm install
# 개발 서버 실행 (http://localhost:4321)
npm run dev
# 프로덕션 빌드
npm run build
# 빌드 결과 미리보기
npm run preview# 이력서 PDF 생성
npm run generate-pdf검색 타입:
- 전체: 제목, 설명, 태그, 내용 모두 검색
- 제목: 제목만 검색
- 내용: 본문 내용만 검색
- 태그: 태그만 검색
구현 방식:
- 서버 사이드에서 MDX 파일을 읽어 본문 추출
- 마크다운 문법 제거 후 클라이언트에 전달
- 클라이언트 사이드에서 실시간 필터링
- URL 쿼리 파라미터로 검색 상태 유지
- 페이지당 10개 포스트 표시
- 검색 결과에 따라 동적으로 페이지 수 조정
- URL 쿼리 파라미터로 페이지 번호 유지
- Astro의
Image컴포넌트 사용 - Sharp를 통한 자동 최적화
- WebP 형식으로 변환
- 반응형 이미지 제공
- 각 페이지별 메타 태그 설정
- Open Graph 태그로 소셜 미디어 공유 최적화
- 자동 사이트맵 생성
- RSS 피드 제공
- Canonical URL 설정
src/content.config.ts에 새 컬렉션 정의:
const newCollection = defineCollection({
loader: glob({ base: './src/content/newCollection', pattern: '**/*.{md,mdx}' }),
schema: ({ image }) => z.object({
title: z.string(),
// ... 스키마 정의
}),
});
export const collections = { blog, resume, project, newCollection };src/content/newCollection/폴더 생성 및 MDX 파일 작성src/pages/newCollection/폴더에 페이지 생성
src/pages/ 폴더에 .astro 파일을 추가하면 자동으로 라우팅됩니다.
예: src/pages/about.astro → /about 경로로 접근 가능
src/components/ 폴더에 .astro 파일을 추가하고 필요한 곳에서 import하여 사용합니다.
-
이미지 경로:
- 컨텐츠에서 이미지 사용 시 상대 경로 사용:
../../assets/... public/폴더의 이미지는 절대 경로:/images/...
- 컨텐츠에서 이미지 사용 시 상대 경로 사용:
-
파일명 규칙:
- 블로그:
YYYYMMDDHHMM.mdx형식 필수 (정렬 및 URL 생성용) - 프로젝트: 대문자 스네이크 케이스 권장 (예:
GOLDEN_TICKET.mdx)
- 블로그:
-
이미지 최적화:
- 큰 이미지는 Sharp의
limitInputPixels설정에 주의 - WebP 형식 사용 권장
- 큰 이미지는 Sharp의
-
빌드 시점:
- 모든 페이지는 빌드 시점에 정적 HTML로 생성됨 (SSG)
- 동적 데이터는 빌드 시점에만 가져올 수 있음
- 플랫폼: Vercel
- 빌드 명령어:
npm run build - 출력 디렉토리:
dist/ - 사이트 URL: https://www.dskim.dev