안동민 개발노트 아이콘

안동민 개발노트

17장 : 실전 프로젝트

프로젝트 기획 및 설계

이 장에서는 앞선 챕터에서 학습한 Next.js 핵심 개념과 고급 주제를 종합해, 실제 웹 애플리케이션을 기획하고 설계하는 과정을 다룹니다. 이론 정리를 넘어 프로젝트 시작 방식, 구조화 방법, 기술 스택 선택, 기능 구현 순서를 실전 기준으로 안내합니다.

이번 절에서는 프로젝트 기획 및 설계에 초점을 맞춰 아이디어 구체화, 요구사항 정의, 기술 스택 선정, 아키텍처 설계, 데이터 모델링까지의 흐름을 정리합니다.


프로젝트 아이디어 구체화 및 목표 설정

프로젝트 시작 단계에서는 아이디어와 목표를 명확히 해야 합니다. 어떤 종류의 애플리케이션을 만들지, 누가 사용할지, 어떤 문제를 해결할지 먼저 정리합니다.

아이디어 도출 및 선정

  • 관심 분야 탐색: 자신이 관심 있거나 잘 아는 분야에서 아이디어를 찾습니다. (예: 독서 기록 앱, 재료 관리 앱, 스터디 그룹 매칭 서비스, 간단한 이커머스 스토어)
  • 문제점 인식: 일상생활이나 업무에서 불편함을 느꼈던 점, 개선이 필요하다고 생각하는 점을 찾아봅니다.
  • 기존 서비스 분석: 유사한 기존 서비스가 있다면, 그들의 장단점을 분석하고 차별화될 수 있는 요소를 모색합니다.
  • 실현 가능성 고려: 주어진 시간과 기술 역량 내에서 구현 가능한 아이디어를 선정합니다. 너무 거창한 아이디어보다는 작고 핵심적인 기능부터 시작하는 것이 좋습니다.

예시 프로젝트 아이디어: 간단한 온라인 북스토어 (Online Bookstore)

  • 문제 정의: 사용자들이 쉽게 책을 검색하고, 상세 정보를 확인하며, 장바구니에 담아 주문할 수 있는 간단한 플랫폼이 필요하다.
  • 대상 사용자: 책 구매에 관심 있는 일반 사용자.
  • 핵심 가치: 사용자 친화적인 인터페이스, 빠른 검색, 간편한 구매 프로세스.

프로젝트 목표 설정 (SMART 원칙)

선정된 아이디어를 바탕으로 구체적인 목표를 설정합니다. SMART 원칙(Specific, Measurable, Achievable, Relevant, Time-bound)을 적용하면 좋습니다.

  • S (Specific): 사용자가 책을 검색하고, 상세 페이지를 보고, 장바구니에 담아 가상으로 주문할 수 있는 웹 애플리케이션 개발.
  • M (Measurable): 최소 50권의 책 데이터 구축, 검색 기능 응답 시간 1초 이내, 장바구니 및 주문 프로세스 구현.
  • A (Achievable): Next.js와 기본적인 웹 기술 스택(MongoDB/PostgreSQL, Route Handlers/Server Actions)만으로 구현 가능.
  • R (Relevant): Next.js 학습 내용을 총체적으로 적용하며, 실제 서비스 개발 경험 습득에 기여.
  • T (Time-bound): 4주 이내에 핵심 기능 개발 및 배포 완료.

요구사항 정의 및 기능 목록 작성

프로젝트 기획 및 설계에서는 요구사항, 데이터 모델, 화면 범위, 기술 선택 기준을 정리합니다.

프로젝트의 목표를 달성하기 위해 필요한 기능들을 구체적으로 정의합니다. 사용자 관점에서 어떤 기능을 제공해야 하는지 상세하게 나열합니다.

핵심 기능 (MVP)

최소 기능 제품(MVP - Minimum Viable Product)은 프로젝트의 핵심 가치를 전달할 수 있는 최소한의 기능 집합입니다. MVP를 먼저 개발하여 빠르게 피드백을 받고 점진적으로 기능을 확장합니다.

  • 사용자 인증 (선택 사항): 회원가입, 로그인, 로그아웃 (간단한 북스토어라면 초기 MVP에서는 제외 가능)
  • 도서 목록 조회: 모든 도서 목록을 페이지네이션과 함께 표시.
  • 도서 검색: 도서 제목, 저자 등으로 검색.
  • 도서 상세 정보: 특정 도서의 상세 정보(제목, 저자, 설명, 가격, 이미지 등) 표시.
  • 장바구니 기능: 도서 추가, 수량 변경, 도서 삭제.
  • 주문 기능 (가상): 장바구니의 도서를 가상으로 주문 (결제 시스템 연동은 MVP에서 제외).

추가 기능 (향후 확장 고려)

MVP 이후 확장할 수 있는 기능들을 미리 구상해 봅니다.

  • 사용자 리뷰 및 평점 시스템.
  • 위시리스트 기능.
  • 추천 도서 기능 (개인화).
  • 관리자 페이지 (도서 추가/수정/삭제, 주문 관리).
  • 실제 결제 시스템 연동 (Stripe, Toss Payments 등).
  • 국제화 (i18n) 지원.
  • 푸시 알림.

기술 스택 선정

Next.js를 기반으로 하지만, 백엔드, 데이터베이스, 스타일링, 배포 등 전반적인 기술 스택을 결정합니다.

프론트엔드 (Next.js 기반)

  • 프레임워크: Next.js (React 기반)
    • 렌더링: 정적 렌더링(정적인 정보 페이지), 동적 렌더링(검색 결과, 사용자별 장바구니), 클라이언트 컴포넌트(장바구니, 주문, 검색 입력)를 적절히 활용.
    • 데이터 페칭: fetch API, SWR 또는 React Query.
  • 타입스크립트: 안정성과 개발 생산성 향상을 위해 TypeScript 사용.
  • 스타일링:
    • CSS Modules: 컴포넌트별 스코프 CSS.
    • Tailwind CSS: 유틸리티 우선 CSS 프레임워크 (빠른 UI 개발).
    • Styled-components / Emotion (선택 사항): 컴포넌트 기반 스타일링. (이 프로젝트에서는 Tailwind CSS를 주력으로 사용)
  • 폼 관리: React Hook Form (폼 유효성 검사 및 상태 관리).

백엔드 및 API

  • API 구현 방식: App Router 기준의 Route Handlers 또는 Server Actions.
    • 간단한 애플리케이션이므로 별도의 백엔드 서버 없이 Next.js 서버 기능을 활용.
  • 인증: NextAuth.js (소셜 로그인 및 세션 관리) - 선택 사항, MVP에서는 제외 가능.
  • 데이터베이스: NoSQL 또는 RDB
    • MongoDB (NoSQL): 유연한 스키마, 빠른 개발 (Mongoose ODM).
    • PostgreSQL (RDB): 관계형 데이터, 안정성 (Prisma ORM 또는 raw SQL).
    • (예시 프로젝트에서는 MongoDB와 Mongoose를 선택)

배포

  • 호스팅: Vercel (Next.js에 최적화된 배포 플랫폼).
  • 데이터베이스 호스팅: MongoDB Atlas (클라우드 MongoDB 서비스).

아키텍처 설계

애플리케이션의 전체적인 구조와 데이터 흐름을 시각화합니다.

시스템 아키텍처 다이어그램

설명
  • User Browser: 사용자가 웹 애플리케이션에 접근하는 클라이언트.
  • Vercel CDN / Edge: 사용자의 요청을 가까운 네트워크 계층에서 받아 정적 자산, CDN 캐시, ISR 캐시 등으로 응답 가능한지 먼저 확인. 캐시로 해결되지 않거나 사용자별 처리가 필요한 요청만 앱 런타임으로 전달.
  • Next.js App on Vercel: Next.js 애플리케이션의 React 컴포넌트, 정적/동적 렌더링, 캐싱 정책을 담당.
  • Vercel Functions: Route Handlers 또는 Server Actions로 구현된 서버 로직. 주문 생성, 데이터 검증처럼 서버 권한이 필요한 요청을 처리.
  • MongoDB Atlas: 클라우드 기반 MongoDB 데이터베이스. 도서 정보, 장바구니 데이터, 주문 정보 등을 저장.

폴더/파일 구조 설계

App Router 기반으로 프로젝트 구조를 설계합니다.

route.ts # GET (상세), PUT (수정), DELETE (삭제)
route.ts # GET (목록), POST (생성)
route.ts # 장바구니 요청 처리
page.tsx # 도서 상세 페이지 (동적 라우팅)
page.tsx # 도서 목록 페이지
page.tsx # 장바구니 페이지
page.tsx # 주문 페이지
layout.tsx # 전역 레이아웃
page.tsx # 홈 페이지
loading.tsx # 전역 로딩 UI
error.tsx # 전역 에러 UI
not-found.tsx # 404 페이지
BookCard.tsx
Header.tsx
Footer.tsx
CartItem.tsx
...
db.ts # 데이터베이스 연결 및 모델 정의
utils.ts # 일반 유틸리티 함수
constants.ts # 상수 정의
favicon.ico
manifest.json
globals.css
.env.local # 로컬 환경 변수
next.config.js # Next.js 설정
tailwind.config.ts # Tailwind CSS 설정
tsconfig.json # TypeScript 설정
package.json # 프로젝트 의존성 및 스크립트

데이터 모델링

애플리케이션이 다룰 데이터의 구조를 정의합니다. NoSQL (MongoDB)을 기준으로 예시를 들어보겠습니다.

주요 엔티티 식별

  • Book: 도서 정보.
  • User: 사용자 정보 (인증 기능 구현 시).
  • CartItem: 장바구니에 담긴 도서 항목.
  • Order: 주문 정보.

스키마 정의 (MongoDB/Mongoose 예시)

lib/db.ts 또는 models/ 디렉토리 내에 정의
lib/db.ts 또는 models/Book.ts
import mongoose, { Schema, Document } from 'mongoose';

// Book 스키마 정의
export interface IBook extends Document {
  title: string;
  author: string;
  description: string;
  price: number;
  imageUrl: string;
  isbn: string;
  publishedDate: Date;
  genre: string[];
  stock: number;
}

const BookSchema: Schema = new Schema({
  title: { type: String, required: true },
  author: { type: String, required: true },
  description: { type: String, required: true },
  price: { type: Number, required: true },
  imageUrl: { type: String, required: true },
  isbn: { type: String, required: true, unique: true },
  publishedDate: { type: Date, default: Date.now },
  genre: [{ type: String }],
  stock: { type: Number, default: 0 },
});

// 이미 정의된 모델이 없으면 생성
const Book = mongoose.models.Book || mongoose.model<IBook>('Book', BookSchema);

// CartItem 스키마 정의 (사용자 인증 후 User 모델과 연결)
export interface ICartItem extends Document {
  userId: mongoose.Types.ObjectId; // User 모델의 ID
  bookId: mongoose.Types.ObjectId; // Book 모델의 ID
  quantity: number;
  addedAt: Date;
}

const CartItemSchema: Schema = new Schema({
  userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },
  bookId: { type: Schema.Types.ObjectId, ref: 'Book', required: true },
  quantity: { type: Number, required: true, min: 1 },
  addedAt: { type: Date, default: Date.now },
});

const CartItem = mongoose.models.CartItem || mongoose.model<ICartItem>('CartItem', CartItemSchema);

// Order 스키마 정의
export interface IOrder extends Document {
  userId: mongoose.Types.ObjectId; // User 모델의 ID
  items: Array<{
    bookId: mongoose.Types.ObjectId;
    quantity: number;
    priceAtPurchase: number; // 구매 시점의 가격
  }>;
  totalPrice: number;
  orderDate: Date;
  status: 'pending' | 'completed' | 'cancelled';
}

const OrderSchema: Schema = new Schema({
  userId: { type: Schema.Types.ObjectId, ref: 'User', required: true },
  items: [
    {
      bookId: { type: Schema.Types.ObjectId, ref: 'Book', required: true },
      quantity: { type: Number, required: true },
      priceAtPurchase: { type: Number, required: true },
    },
  ],
  totalPrice: { type: Number, required: true },
  orderDate: { type: Date, default: Date.now },
  status: { type: String, enum: ['pending', 'completed', 'cancelled'], default: 'pending' },
});

const Order = mongoose.models.Order || mongoose.model<IOrder>('Order', OrderSchema);

// 데이터베이스 연결 함수
let cachedDb = null;
export async function connectToDatabase() {
  if (cachedDb) {
    return cachedDb;
  }
  const MONGODB_URI = process.env.MONGODB_URI;
  if (!MONGODB_URI) {
    throw new Error('Please define the MONGODB_URI environment variable inside .env.local');
  }
  const conn = await mongoose.connect(MONGODB_URI, {
    bufferCommands: false, // Node.js 드라이버의 기본 버퍼링을 비활성화
  });
  cachedDb = conn;
  return conn;
}

export { Book, CartItem, Order };

프로젝트 기획 및 설계 단계는 실제 개발의 기초를 다지는 가장 중요한 과정입니다. 이 단계에서 충분한 시간을 투자하여 명확한 목표, 구체적인 기능, 적절한 기술 스택, 그리고 견고한 아키텍처를 정의한다면, 이후 개발 과정의 효율성과 프로젝트의 성공 가능성을 크게 높일 수 있습니다. 다음 절에서는 이 설계를 바탕으로 실제 프로젝트 환경을 설정하고 개발을 시작하는 방법을 다루겠습니다.

아래 다이어그램은 MVP 기능, 기술 스택, 백엔드 API, 배포 흐름을 프로젝트 설계 관점에서 묶어 보여줍니다.

아래 다이어그램은 프로젝트 기획과 설계를 요구사항 정의, 데이터 모델링, 화면 구조, 배포 제약 순서로 정리합니다.