Next.js 풀스택 블로그 개발기

힘센캥거루
2026년 1월 14일(수정됨)
4
16

웹개발을 처음 접한지 1년정도 되었을 때, 나만의 블로그를 갖고싶다는 생각을 하게 되었다.

그래서 6개월 정도 여기에만 매달려서 만들어보게 되었다.

Next.js 풀스택 블로그 개발기-1

프론트 앤드에서의 기능은 아래 김도형님의 블로그를 참고하는 것으로 충분할 듯하다.

나도 mdx를 이용해 블로그를 만드는데는 채 1주일도 걸리지 않았다.

사실 블로그를 운영하는데 프론트 앤드만 있어도 큰 문제는 없었다.

한동안은 mdx를 만들어 프론트 앤드 개발만으로도 충분하다 생각했으나, 어디서나 웹에 접속해 글을 쓸 수 있는 풀스택 블로그에 대한 꿈을 접을 수 없었다.

1. 기능

기능은 별거 없다.

글을 올리고, 그리고 확인할 수 있다.

Next.js 풀스택 블로그 개발기-2

로그인을 하면 오른쪽 상단의 버튼 형태가 바뀌게 된다.

그리고 클릭하면 글을 업로드 할 수 있다.

아래 영상을 보면 글을 올리고 업로드 하는 과정이 있다.

이미지 변환 과정이 있는데, 업로드된 모든 이미지들은 가장 효율이 좋은 avif 형태로 관리한다.

유튜브는 주소를 붙여넣기만 하면 위와 같이 삽입도 가능하다.

표 관리 기능의 아이디어는 티스토리에서 얻었다.

Next.js 풀스택 블로그 개발기-3

표 위로 focus가 on 되면 상단에 표를 추가하거나, 삭제하는 툴바가 뜬다.

물론 임시저장도 가능하다.

편집기 안에서 cmd+s를 누르거나, ctrl+s를 누르면 저장된다.

2. 아키텍쳐

아키텍쳐가 뭔가 멋져보이는데 한글로 그냥 구조다.

처음 서버로 들어온 요청은 Caddy가 리버스 프록시로 분배해준다.

프론트 앤드만 있다면 mdx를 그대로 변환해서 전송하겠지만, 백앤드를 만들었으니 이걸 Next.js와 Prisma로 붙여주었다.

Next.js 풀스택 블로그 개발기-4

다들 알겠지만 유저에게서 오는 데이터들을 그대로 백엔드에 갖다 넣었다가는 바로 해킹당한다.

반드시 API로 검증 후에 넣어준다.

Next.js 풀스택 블로그 개발기-5

한번은 블로그에 댓글이 많이 달리길 바라는 마음에 누구나 댓글을 달 수 있도록 API 개방해 두었다.

그랬더니 한놈이 해당 API로 쿼리 인젝션 공격을 계속 퍼부어서 댓글이 100개 가량 달려 있었다.

svg이미지 내부에 fetch와 명령어를 삽입해 해킹을 시도한 놈도 있었다.

아마 중국 어딘가에 나도 모르는 내가 멀쩡히 걸어다니고 있을지도 모를 일이다.

3. 에디터

Next.js 풀스택 블로그 개발기-6

가장 정성들여서 만든게 에디터이다.

에디터는 Tiptap에 여러가지 기능들을 덧붙여 제작했다.

그러다보니 Tiptap 관련 Component만 해도 10개가 넘어간다.

Next.js 풀스택 블로그 개발기-7

이미지 삽입 같은 경우는 아래와 같이 구현했다.

  const editor = useEditor({
    extensions: editorExtensions,
    content,
    onUpdate: ({ editor }) => {
      onChange(editor.getHTML());
    },
    editorProps,
    immediatelyRender: false, 
  });

  const { uploadProgress, uploadImage, clearProgress } = useImageUpload({
    onUploadComplete: (imageUrl, isAnimated) => {
      if (editor) {
        try {
          editor
            .chain()
            .focus()
            .insertContent([
              {
                type: "image",
                attrs: {
                  src: imageUrl,
                  alt: "업로드된 이미지",
                  "data-animated": isAnimated || false,
                },
              },
              {
                type: "paragraph",
                content: [],
              },
            ])
            .run();
        } catch (error) {
          console.error("이미지 삽입 오류:", error);
        }
      }
    },
  });

성능면에서 이점을 얻기 위해 HTML을 그대로 저장하고 로드했다.

Tiptap에서 백엔드로 저장할 때는 여러가지 과정을 추가했다.

코드블럭, 구글맵, 제목, 이미지, 링크 프리뷰 등 다양한 처리를 미리 한 뒤 content와 processedContent를 따로 저장했다.

4. 백앤드 스키마

최근에 다국어 서비스를 하면서, 한번 만든 백앤드 스키마를 변경하는건 재앙이라는 걸 알게 되었다.

새삼 스키마의 중요성을 강조하시던 교수님의 말씀이 생각났다.

만약 블로그 백앤드까지 생각하고 있다면, 어떤 서비스를 제공할 것인지를 오랫동안 고민해보길 바란다.

이것 저것 추가하다보니 너무 커져버린 스키마라 부끄럽지만 공개해본다.

model Post {
  id               String          @id @default(cuid())
  title            String
  slug             Int             @unique @default(autoincrement())
  excerpt          String
  content          String
  processedContent String?         
  thumbnail        String?
  published        Boolean         @default(false)
  createdAt        DateTime        @default(now())
  updatedAt        DateTime?
  likes            Int             @default(0)
  views            Int             @default(0)
  comments         Comment[]
  likesRows        PostLike[]
  viewDedups       PostViewDedup[]
  notifications    Notification[]
  locales          PostLocale[]
  author           User            @relation(fields: [authorId], references: [id], onDelete: Cascade)
  authorId         String
  category         String
  @@map("posts")
}

5. 후기

이제 다음 질문에 대답해볼 차례이다.

블로그를 만드는데 백앤드까지 필요한가?

다 만들고 나니 굳이?라는 생각이 든다.

결국 워드 프레스가 엄청 쉬운 길이었다는걸 깨닫게 되었다.

백앤드와 API를 구현하는 순간부터 정말 생각해야 할 것들이 많아진다.

최근 react2shell 이슈 때는 몇 분 단위로 공격받고, 터미널에서 처음보는 명령어들이 자꾸 나와서 몇 일 동안 힘들었다.

지금도 몇일 단위로 npm audit으로 보안을 점검하고 수정한다.

가끔 DB 스키마를 변경하고 마이그레이션이 꼬일 때는 식은땀이 난다.

그래도 뒤돌아보면 백앤드를 구현하면서 많은 부분들을 배우게 되었고, 내 손으로 기능을 구현 가능한 블로그를 갖게 된 점은 좋은 것 같다.

앞으로는 블로그 기능 추가보다는 다른 프로젝트를 진행하면서 내 포트 폴리오를 풍성하게 만들어 보고 싶다.

관련 글

Caddy를 이용한 Nextjs 무중단 배포(로컬서버)
Caddy를 이용한 Nextjs 무중단 배포(로컬서버)
홈페이지에 뭔가 자꾸 얹고 싶은 욕심이 들 때 마다 빌드를 했더니, 그 사이에 가끔 접속하는 사람이 종종 있긴 한것 같다.그러다 보니 서치콘솔에서 점수가 점점 하락하는 현상이 발생했다.이대로는 안될 것 같아 무중단 배포를 하는 방법을 생각해 보게 되었다.1. 대표적인 ...
구글 검색 색인 자동화 - Web Search Indexing API
구글 검색 색인 자동화 - Web Search Indexing API
지난번 IndexNow에 이어, 구글도 자동화를 해보기로 했다.찾아보니 구글은 API로 Web Search Indexing이라는 걸 지원하고 있었다.1. 허용범위공식적으로 해당 API가 지원하는 범위는 채용공고와 스트리밍 영상 서비스이다.실시간이 중요한 내용에 대해 색...
검색 색인 생성 자동화 - IndexNow
검색 색인 생성 자동화 - IndexNow
Bing에 검색등록을 하다가 알게 되었는데, Bing에서는 IndexNow라는 기능을 제공한다.핵심은 API 키를 이용해서 글을 쓰자마자 바로 색인 요청을 날릴 수 있다는 것.아래와 같은 요청을 fetch로 만들고, 글쓰기에 연동해 놓으면 글을 DB에 저장함과 동시에 ...
Nextjs, React 서버 해킹당한 경험 - React2Shell
Nextjs, React 서버 해킹당한 경험 - React2Shell
맨 처음 보안 이슈를 접했던건 12월 5일 새벽이었다.리액트에서 인증 없이 원격 코드 실행이 가능하다는 것.해당 뉴스를 접하고 다른 사람에게 알렸지만, 나는 괜찮으려니 싶어 아무 생각없이 넘겼다.1. 해킹 흔적 발견그런데 블로그 코드를 업데이트 하려고 접속했더니 터미널...
블로그에 다국어 기능 추가하기(NextJS, next-intl, Vercel AI SDK)
블로그에 다국어 기능 추가하기(NextJS, next-intl, Vercel AI SDK)
최근 블로그에 다국어 기능이 필요하다는 생각이 들었다.그래서 next-intl을 이용해 다국어 서비스를 구현해보기로 했다.1.i18n먼저 다국어 서비스를 할 때는 지켜야 할 원칙들이 있다.이걸 internationalization이라고 하는데, 무척 길기에 첫글자 i와...
Nextjs에 다국어 설정하기
Nextjs에 다국어 설정하기
내 블로그에 대한 유입을 늘리기 위해 어떻게 해야 할까 고민하다가 다국어 설정을 해보기로 했다.다양한 방법을 찾아 보았는데, 일단 첫걸음은 언어에 대해 다른 라우팅을 하는 것.next-intl을 이용해 해보기로 했다.1. 설치yarn add next-intl2. 적용적...

댓글을 불러오는 중...