안동민 개발노트

안동민 개발노트

프로젝트 기획 및 설계단계별 구현 가이드도서 목록·상세·검색장바구니 구현주문 및 검색전역 레이아웃 및 배포코드 리뷰 및 최적화추가 기능 확장 제안
본문 시작
  1. 홈
  2. 문서
  3. Next.js
  4. 17장 : 실전 프로젝트
  5. 프로젝트 기획 및 설계
  1. Next.js
  2. 프로젝트 기획 및 설계

프로젝트 기획 및 설계

온라인 북스토어의 사용자·문제·MVP를 정의하고 기술 스택, 화면·API 경계, 도서·주문 데이터 모델을 설계합니다.

이 장에서는 앞선 챕터에서 학습한 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주 이내에 핵심 기능 개발 및 배포 완료.

50권·1초·4주는 계획의 목표값입니다. 뒤의 시드는 2권 예시이며 검색 응답 시간을 측정한 결과를 제시하는 것은 아닙니다. 측정할 때는 데이터 규모와 기기·네트워크 조건도 함께 정합니다.


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

프로젝트의 목표를 달성하기 위해 필요한 기능들을 구체적으로 정의합니다.

사용자 관점에서 어떤 기능을 제공해야 하는지 상세하게 나열합니다.

핵심 기능 (MVP)

최소 기능 제품(MVP - Minimum Viable Product)은 프로젝트의 핵심 가치를 전달할 수 있는 최소한의 기능 집합입니다.

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 서버 기능을 활용.
  • 인증: Auth.js(소셜 로그인 및 세션 관리). 장바구니와 주문 Server Action은 인증된 사용자 ID를 기준으로 동작.
  • 데이터베이스: NoSQL 또는 RDB
    • MongoDB (NoSQL): 유연한 스키마, 빠른 개발 (Mongoose ODM).
    • PostgreSQL (RDB): 관계형 데이터, 안정성 (Prisma ORM 또는 raw SQL).
    • (예시 프로젝트에서는 MongoDB와 Mongoose를 선택)

배포

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

아키텍처 설계

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

시스템 아키텍처

북스토어의 화면·서버·저장소

북스토어의 화면·서버·저장소

북스토어의 화면·서버·저장소브라우저는 Next.js 서버에 요청하고 서버가 MongoDB를 조회하거나 변경한다.브라우저목록 · 장바구니 UINext.js 서버렌더링 · 인증 · 액션MongoDB Atlas도서 · 장바구니 · 주문
북스토어의 화면·서버·저장소브라우저에서 서버로, 서버에서 데이터베이스로 이어지는 요청 경계.브라우저목록 · 장바구니 UINext.js 서버렌더링 · 인증 · 액션MongoDB Atlas도서 · 장바구니 · 주문

기능의 책임을 나타낸 구조입니다. 정적 자산·캐시 응답은 CDN에서 처리할 수 있고, 렌더링과 Server Action이 별도 서버로 분리된다는 뜻은 아닙니다.

Auth.js는 서버 세션에서 사용자 식별 정보를 제공하고, 장바구니·주문 액션은 이 ID로 조회 대상을 제한합니다. 데이터베이스 연결 문자열과 권한 검사는 서버 경계에 둡니다.

폴더/파일 구조 설계

App Router 기반으로 프로젝트 구조를 설계합니다. 아래 트리에서 # 뒤는 설명이며 실제 파일·폴더 이름에는 포함하지 않습니다.

route.ts # Auth.js GET·POST 핸들러
page.tsx # 도서 상세 페이지 (동적 라우팅)
page.tsx # 검색·페이지네이션 도서 목록
loading.tsx # 목록 로딩 UI
page.tsx # 장바구니 페이지
page.tsx # OAuth 로그인 페이지
page.tsx # 주문 페이지
page.tsx # 주문 완료 페이지
layout.tsx # 전역 레이아웃
page.tsx # 홈 페이지
globals.css # Tailwind CSS 전역 스타일
cart.ts # 장바구니 추가·수정·삭제
order.ts # 트랜잭션 주문 생성
BookCard.tsx
AddToCartButton.tsx
CartItemCard.tsx
Footer.tsx
Header.tsx
PlaceOrderButton.tsx
SearchInput.tsx
auth.ts # Auth.js 서버 세션 헬퍼
db.ts # MongoDB 연결
Book.ts
CartItem.ts
Order.ts
seed.ts # 초기 도서 데이터 삽입
cart.ts # 직렬화된 장바구니 DTO
next-auth.d.ts # 세션 타입 확장
book-placeholder.svg
auth.ts # Auth.js 설정과 handlers·auth
.env.local # 로컬 환경 변수
next.config.ts # Next.js 설정
postcss.config.mjs # Tailwind CSS PostCSS 플러그인
tsconfig.json # TypeScript 설정
package.json # 프로젝트 의존성 및 스크립트

데이터 모델링

애플리케이션이 다룰 데이터의 구조를 정의합니다.

NoSQL (MongoDB)을 기준으로 예시를 들어보겠습니다.

주요 엔티티 식별

  • Book: 도서 정보.
  • User: Auth.js 공급자와 세션이 관리하는 사용자 식별 정보. 이 MVP는 별도 User 모델을 만들지 않습니다.
  • CartItem: 장바구니에 담긴 도서 항목.
  • Order: 주문 정보.

CartItem은 bookId와 수량을 저장해 도서의 현재 정보와 연결합니다. Order의 각 항목은 bookId와 구매 시점 가격인 priceAtPurchase를 함께 저장하므로, 이후 도서 가격이 바뀌어도 주문 금액을 현재 가격으로 다시 계산하지 않습니다. userId 문자열은 각 장바구니·주문의 소유자를 구분합니다.

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

각 스키마는 폴더 구조에서 정한 models 파일에 하나씩 분리합니다.

다음 Book 모델은 그대로 복사할 수 있는 예시이며, CartItem과 Order 모델은 다음 절에서 같은 방식으로 구현합니다.

models/Book.ts
import mongoose, { Schema, type Model } from 'mongoose';

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

const BookSchema = new Schema<IBook>({
  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 },
}, { timestamps: true });

const Book = (mongoose.models.Book as Model<IBook> | undefined)
  ?? mongoose.model<IBook>('Book', BookSchema);

export default Book;

unique: true는 Mongoose 검증기가 아니라 MongoDB의 고유 인덱스를 만들기 위한 선언입니다. 실제 인덱스가 있어야 중복 ISBN을 막을 수 있습니다. 현재 Book 스키마에는 제목·저자 검색 인덱스나 가격·재고의 음수·정수 검증이 없으므로, 선언한 제약과 추가할 정책을 구분합니다.

다음 절에서 CartItem과 Order를 정의하고 이 구조를 실제 화면과 연결합니다.

WebSocket 통합

이전 페이지

단계별 구현 가이드

다음 페이지

이 페이지의 목차

프로젝트 아이디어 구체화 및 목표 설정아이디어 도출 및 선정프로젝트 목표 설정 (SMART 원칙)요구사항 정의 및 기능 목록 작성핵심 기능 (MVP)추가 기능 (향후 확장 고려)기술 스택 선정프론트엔드 (Next.js 기반)백엔드 및 API배포아키텍처 설계시스템 아키텍처폴더/파일 구조 설계데이터 모델링주요 엔티티 식별스키마 정의 (MongoDB/Mongoose 예시)