🔎 프로젝트 소개

GitHub 저장소를 Headless CMS처럼 활용하여 서버 없이 콘텐츠 관리 및 댓글 시스템을 구현한 블로그입니다. GitHub REST API를 활용하여 전체 기능을 구성했습니다.
코드 에디터에서 .md 파일을 작성하는 것에 불편함을 느꼈고, 글 저장소와 개발/배포 레퍼지토리를 분리하고자 개발하였습니다.
포스트 목록 조회하기
- 전체 포스트 목록을 조회할 수 있으며, 카테고리 별로 나누어서 볼 수 있습니다.
포스트 상세 조회, 생성, 수정, 삭제
- 마크다운 에디터로 포스트를 편집, 생성할 수 있습니다.
- 포스트를 수정, 삭제할 수 있으며 깃허브 내에 커밋으로 히스토리를 저장/관리합니다.
댓글 작성, 수정, 삭제
- 인증된 사용자는 포스트에 댓글을 작성, 수정, 삭제할 수 있습니다.
방명록 작성, 수정, 삭제
- 인증된 사용자는 마크다운 에디터를 사용하여 방명록을 작성, 수정, 삭제할 수 있습니다.
권한 인증
- Github OAuth 로 로그인할 수 있습니다.
- 계정에 따라 글쓰기 / 댓글,방명록 쓰기 / 읽기 권한이 부여됩니다.
👩🏻💻 개발 내용
1. 블로그 서버 로직 개발
포스트 목록 조회
,포스트 생성/수정/삭제
,포스트 작성/수정 시간 조회
,댓글 생성/수정/삭제
,리소스 업로드
기능을 개발했습니다.
- Github REST Api 를 통해 파일을 불러오고 파싱하여 도메인에 필요한 데이터만 반환합니다.
- @octokit/rest 라이브러리를 사용하여 구현했습니다.
- GitHub API가 반환하는 데이터는 커밋 관련 정보를 포함하며, 요청 시 GitHub 토큰이 필요합니다.
- 이러한 값들을 숨기고 데이터 파싱 로직을 분리하기 위해, Next.js의 API Route를 활용하여 해당 로직들이 서버 사이드에서 동작하도록 했습니다.

- 블로그 글들은 posts 디렉토리 내에 .md 파일로 저장됩니다.
- 글 생성 시, 고정된 이슈 넘버를 부여하여 댓글 저장소를 연결합니다.
- 글 조회 시, 부여된 이슈 넘버로 해당 이슈의 comments 들을 불러와 댓글들을 함께 조회합니다.
2. 마크다운 에디터
- 글을 작성할 때, 마크다운 텍스트를 작성하는 데에 도움을 주는 에디터 기능을 직접 구현했습니다.
- react-markdown 라이브러리를 사용하여 뷰어 기능을 작성했습니다. (텍스트 → html)
- 마크다운 텍스트 관련 로직의 활용성을 높이기 위해, textareaRef 를 받아서 선택한 텍스트에 서식을 적용하는 함수들을 반환하는
useEditMD
을 구현했습니다. changeTextBold
: 텍스트 볼드 처리changeTextItalic
: 텍스트 기울임 처리addHeading
: 제목 서식 추가addQuote
: 인용 서식 추가addList
: 리스트 추가 (unOrdered)addOrderedList
: 숫자 기호 리스트 추가addCode
: 코드 블럭 / 인라인 코드 추가addHorizontal
: 수평선 추가addTable
: 테이블 추가addLink
: 링크 추가addFile
: 파일 추가 (이미지, 비디오 등)
구현한 기능 목록
- 텍스트 선택 또는 커서 이동 후 버튼을 클릭하거나 단축키를 입력하여 편집 가능하도록 했습니다.
- hello 선택 후 ctrl+b → **hello** hello 선택 후 볼드 처리 버튼 클릭 → **hello**
- 단축키 기능의 경우, 발동 조건과 실행 함수를 매개변수로 받아 단축키 이벤트 리스너를 작동시키는
useShortcut
을 구현하였습니다.
3. useActionState, Server Action
- Server Action 기능을 활용하여 스크립트 코드에 의존하지 않고 폼 데이터로 제출이 가능하도록 했습니다.
- fetch 옵션의 tag를 설정하고, revalidateTag 함수를 실행하여 수정이 일어났을 시에만 데이터를 다시 가져옵니다.
- 서버 데이터 수정이 완료된 후에는, server action 내에서 redirect 를 실행해 리다이렉트 시 조건에 따라 화면이 깜빡이는 클라이언트 코드의 문제를 개선하고자 했습니다.
- 폼 제출 / 서버 요청 중 UI 를 제어하기 위해 useActionState 를 활용했습니다.
- isPending 상태일 경우 제출 버튼을 disabled 하여 에러를 방지했습니다.