내 MERN 스택 포트폴리오를 위한 동적 Admin Panel 구축 방법

발행: (2025년 12월 27일 오후 05:56 GMT+9)
7 min read
원문: Dev.to

Source: Dev.to

포트폴리오를 위한 관리자 패널을 구축해야 하는 이유?

처음에는 정적 콘텐츠만 표시하는 간단한 React 포트폴리오를 만들었습니다. 하지만 곧 모든 업데이트마다 코드 수정과 재배포가 필요했으며, 이는 시간도 많이 걸리고 오류가 발생하기 쉬웠습니다.

관리자 대시보드를 구축함으로써 다음을 달성했습니다:

  • 실시간 콘텐츠 업데이트: UI를 통해 프로젝트, 스킬, 기타 프로필 데이터를 추가, 수정, 삭제할 수 있습니다.
  • 보안 접근: JWT 인증을 사용해 나만 로그인하여 콘텐츠를 관리할 수 있습니다.
  • 확장성: 프론트엔드를 수정하지 않고도 새로운 섹션이나 데이터 유형을 쉽게 확장할 수 있습니다.
  • 더 나은 조직화: 하드코딩된 파일 대신 데이터베이스에 포트폴리오 콘텐츠를 저장합니다.

기술 스택 개요

LayerTechnology
프론트엔드React (functional components & hooks)
백엔드Node.js + Express (REST APIs)
데이터베이스MongoDB + Mongoose
인증JWT (JSON Web Tokens)
파일 저장Cloudinary (image & resume uploads)
스타일링CSS Modules + UI libraries

관리자 패널의 주요 기능

  • 프로필 섹션: 바이오, 프로필 사진, 연락처 정보를 업데이트합니다.
  • 스킬: 프로그래밍 스킬을 동적으로 추가, 업데이트 또는 제거합니다.
  • 프로젝트: 프로젝트에 대한 CRUD 작업(제목, 설명, 이미지, 링크).
  • 이력서: 이력서 파일을 업로드하고 업데이트합니다.
  • 인증: 이메일 및 비밀번호를 사용한 보안 로그인, JWT를 이용한 보호된 라우트.

작동 방식 — 아키텍처 분석

1. 백엔드 API 설계

모든 포트폴리오 데이터를 위한 CRUD 작업을 처리하는 RESTful API를 만들었습니다.

예시 라우트

GET    /api/projects          // fetch all projects
POST   /api/projects          // add a new project
PUT    /api/projects/:id      // update project by ID
DELETE /api/projects/:id      // delete project by ID

API는 요청을 검증하고 Mongoose 모델을 사용해 MongoDB 컬렉션과 상호 작용합니다. 인증 미들웨어가 민감한 엔드포인트를 보호합니다.

2. JWT 인증

관리자 패널을 보호하기 위해 다음과 같은 로그인 시스템을 구축했습니다:

  • bcrypt를 사용한 비밀번호 해싱.
  • 로그인 시 JWT 토큰 생성.
  • 프론트엔드와 백엔드 모두에서 유효한 토큰이 필요한 보호된 라우트.

3. React 관리자 대시보드 UI

API 호출을 위해 React 훅과 axios를 사용하여 다음과 같은 컴포넌트를 만들었습니다:

  • Login Page: 인증하고 JWT를 localStorage에 저장합니다.
  • Dashboard: 포트폴리오 내용 개요.
  • Forms: 기술 및 프로젝트 추가/수정을 위한 제어된 폼.
  • File Uploads: 이미지와 이력서 업로드를 위해 Cloudinary API와 통합했습니다.

조건부 렌더링과 로딩 상태가 부드러운 사용자 경험을 제공합니다.

코드 스니펫 — 예시: 관리자 패널에서 프로젝트 가져오기

import React, { useEffect, useState } from "react";
import axios from "axios";

const AdminProjects = () => {
  const [projects, setProjects] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const fetchProjects = async () => {
      try {
        const token = localStorage.getItem("authToken");
        const response = await axios.get("/api/projects", {
          headers: { Authorization: `Bearer ${token}` },
        });
        setProjects(response.data);
      } catch (error) {
        console.error("Error fetching projects:", error);
      } finally {
        setLoading(false);
      }
    };
    fetchProjects();
  }, []);

  if (loading) return <p>Loading projects...</p>;

  return (
    <div>
      <h2>Manage Projects</h2>
      {projects.length === 0 ? (
        <p>No projects found.</p>
      ) : (
        projects.map((project) => (
          <div key={project._id}>
            <h3>{project.title}</h3>
            <p>{project.description}</p>
            {/* Buttons for Edit/Delete can go here */}
          </div>
        ))
      )}
    </div>
  );
};

export default AdminProjects;

도전 과제 및 교훈

  • 파일 업로드 처리: Cloudinary의 서명된 URL을 통합하고 업로드 상태를 관리하는 데 추가적인 주의가 필요했습니다.
  • 상태 관리: 특히 실시간 CRUD 업데이트 후에 백엔드 데이터와 관리자 UI를 동기화하는 것이 React 상태와 효과를 신중하게 사용해야 했습니다.
  • 인증 흐름: 라우트를 보호하고 JWT 토큰을 관리하는 것이 무단 접근을 방지하는 데 중요했습니다.
  • UX 고려사항: 간단하고 효과적인 폼과 명확한 피드백 메시지는 관리자 사용성을 크게 향상시켰습니다.

최종 생각

동적인 관리자 패널을 구축하면서 내 포트폴리오를 정적인 웹페이지에서 재배포 없이 제어할 수 있는 강력한 콘텐츠 관리 시스템으로 변모시켰습니다. 이를 통해 풀스택 개발, API 설계, 보안 인증, 파일 관리 등 현대 웹 개발자에게 필수적인 기술을 직접 체험할 수 있었습니다.

포트폴리오를 구축하거나 개선하려는 계획이 있다면, 관리자 대시보드를 추가하는 것을 강력히 추천합니다. 이는 기술 역량을 보여줄 뿐만 아니라 장기적으로 시간과 노력을 크게 절감해 줍니다.

포트폴리오를 직접 확인해 보세요:
[http://your-portfolio-link.com] (실제 URL로 교체)


https://adithyan-phi.vercel.app

질문이 있거나 경험을 공유하고 싶으신가요? 아래에 댓글을 남겨 주세요!


코딩 즐겁게 하세요!

Back to Blog

관련 글

더 보기 »