project-thumbnail

SEOKO

개발자 지석호의 포트폴리오 및 블로그 웹 서비스입니다.

2022-12-21~진행중

프로젝트 소개

SEOKO는 개발자 지석호의 포트폴리오 및 블로그 기능을 포함한 웹 서비스입니다. 저의 경험과 공부한 내용을 정리하여 기록하고 성장하는 과정을 보여드리기 위해 개발하였습니다. 이 서비스는 지속적으로 리팩토링하면서 꾸준히 개발할 예정입니다.

기술 스택

LANGUAGE

  • typescript@^5.0.4: Typescript를 사용하여 타입 안정성을 확보하고 코드 가독성을 높입니다.

FRONT-END

  • next@13.4.19: Next.js를 사용하여 서버사이드 렌더링 및 정적 사이트 생성을 구현합니다. app router를 사용하여 페이지 라우팅을 구성합니다.
  • @tanstack/react-query@^4.29.19: 데이터를 관리하고 캐싱을 사용하여 API 요청을 최적화합니다. data hydration을 통해 server-side에서 pre-fetching을 구현합니다.
  • axios@^1.4.0: API 요청을 보내기 위해 axios를 사용합니다. interceptor를 사용하여 인증 여부를 확인합니다.
  • tailwindcss@^3.0.7: Tailwind CSS를 사용하여 스타일을 구성합니다. 기존 emotion을 사용하여 스타일링을 구현하였으나 css-in-js가 server component에서 동작하지 않아 변경하였습니다. css variable과 tailwind theme를 매칭하여 light/dark mode를 구현합니다.

BACK-END

  • @nestjs/cli@^10.0.0: NestJS를 사용하여 서버를 구성합니다. repository pattern을 통해 model과 service의 결합도를 낮추고 유지보수성을 높입니다.
  • @nestjs/jwt@^10.1.0: JWT를 사용하여 access token과 refresh token을 발급합니다. 해당 token을 통해 사용자 인증을 구현합니다.
  • mongoose@^7.3.4: MongoDB ODM 라이브러리인 Mongoose를 사용하여 data object와 DB schema를 매핑합니다.
  • pm2@^5.3.0: 무중단 배포를 위해 pm2를 사용합니다. docker container에서 실행되는 app의 상태를 관리합니다.

DEVOPS

  • MongoDB: MongoDB를 사용하여 데이터베이스를 구축합니다. 스키마를 정의하고 Replica Set을 구성하여 transaction을 지원합니다.
  • docker: Docker를 사용하여 컨테이너화된 서비스를 구축합니다. Dockerfiledocker-compose를 사용하여 개발 환경과 배포 환경을 구성합니다.
  • github actions: Github Actions를 사용하여 CI/CD 파이프라인을 구축합니다. PR이 올라올 때마다 빌드 및 테스트를 진행하고 배포를 진행합니다.
  • nhn cloud: NHN Cloud를 사용하여 서버 인스턴스를 생성하고 도메인을 연결합니다. nginx를 사용하여 reverse proxy를 구성하고 letsencrypt를 사용하여 SSL 인증서를 발급하여 https를 적용합니다.

Architecture

architecture.png

architecture.png

핵심/페이지 기능

Infinite Scroll
무한 스크롤을 적용하여 사용자 경험을 향상시킵니다. Intersection Observer API를 사용하여 마지막 요소가 감지되면 다음 페이지의 게시글을 불러옵니다.

Dark Mode
post_image
Tailwind CSSdark mode를 사용하여 다크 모드를 구현합니다. 사용자가 토글 버튼을 클릭하여 다크 모드로 전환할 수 있습니다.

Markdown - Editor
@uiw/react-md-editor를 사용하여 마크다운 에디터를 구현했습니다. 기존 라이브러리에서 제공하는 image 업로드 기능에 문제가 있어 직접 커스텀하여 이미지 업로드 기능을 구현했습니다.
1const imageHandler = async (e: React.ChangeEvent<HTMLInputElement>) => {
2  const file = e.target.files?.[0];
3
4  if (!file) return;
5
6  const encodedFile = new File([file], encodeURI(file.name), { type: file.type });
7
8  const formData = new FormData();
9
10  formData.append("image", encodedFile);
11
12  const imageUrl = await mutateAsync(formData);
13
14  // 이미지 업로드 후 에디터에 이미지 추가
15  const textarea = document.querySelector(".w-md-editor-text-input") as HTMLTextAreaElement;
16
17  const api = new commands.TextAreaTextApi(textarea);
18
19  const modifyText = `![](${imageUrl})\n`;
20
21  api.replaceSelection(modifyText);
22};

Markdown - Viewer
post_image
기존 viewer는 react-markdown를 사용하여 구현하였으나 해당 라이브러리는 빌드시 용량이 크고 compile 시간이 오래 걸려 markdown-to-jsx로 변경하였습니다. 내장 기능을 사용하여 커스텀 컴포넌트를 mdx 형식으로 적용할 수 있도록 구현하였으며 code highlight, table of contents등을 구현하였습니다.

Main Page

main

main

간단한 소개와 최신순 게시글 목록을 확인할 수 있습니다.
게시글 목록을 클릭하여 상세 페이지로 이동할 수 있으며 태그를 클릭하여 해당 태그를 가진 게시글 목록을 확인할 수 있습니다.
검색창을 통해 제목, 내용과 매칭되는 게시글을 검색할 수 있습니다. 디바운스를 적용하여 API 요청을 최적화하였습니다.
또한 무한 스크롤을 적용하여 페이지 네이션을 구현하였습니다.

Series Page

series/detail

series/detail

작성된 게시글을 시리즈로 묶어서 관리할 수 있습니다. 해당 시리즈를 클릭하여 시리즈에 속한 게시글 목록을 확인할 수 있습니다.
시리즈 상세 페이지에서는 시리즈에 속한 게시글 목록을 확인할 수 있습니다. 상단 버튼을 통해 오름차순, 내림차순으로 정렬할 수 있습니다.
이전 게시글 목록 컴포넌트를 재사용하여 무한 스크롤을 적용하였습니다.

Project Page

project/detail

project/detail

프로젝트 목록을 확인할 수 있습니다. 각 년도별로 정리되어 있으며 프로젝트를 클릭하여 상세 페이지로 이동할 수 있습니다.

About Page

about

about

지석호라는 개발자에 대한 소개와 정보를 확인할 수 있습니다. skill, experience, project를 확인할 수 있으며 skill과 experience는 로그인 후 수정할 수 있습니다.

Write Page

post/project

post/project

해당 페이지에 경우 post/project 모두 동일한 에디터를 사용하며 markdown을 사용하여 작성할 수 있습니다. 이미지 업로드 기능을 구현하였으며 이미지를 업로드하면 해당 이미지를 에디터에 추가할 수 있습니다.

Post Detail Page

좌측 좋아요/중앙 마크다운/우측 TOC

좌측 좋아요/중앙 마크다운/우측 TOC

게시글의 상세 내용을 확인할 수 있습니다. 좌측에서는 toggle 버튼을 통해 좋아요를 누를 수 있습니다. 우측에서는 TOC를 확인할 수 있으며 클릭시 해당 위치로 이동합니다. 최하단으로 이동하면 댓글을 작성할 수 있습니다.

관련 문서

Yarn Berry 블로그 적용 후기!
Next.js + Apollo Client 적용하기