프로젝트 기획 및 설계
온라인 북스토어의 사용자·문제·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권 예시이며 검색 응답 시간을 측정한 결과를 제시하는 것은 아닙니다. 측정할 때는 데이터 규모와 기기·네트워크 조건도 함께 정합니다.
작은 완료 기준을 정하기 첫 실습의 완료 기준은 두 권의 도서가 보이고, 로그인한 사용자가 자기 장바구니를 바꾼 뒤 가상 주문의 DB 변화를 확인하는 것입니다. 50권과 1초 목표의 검사는 별도 규모로 준비해야 합니다. 사용자 동작, 서버에서 확인할 소유자, 저장할 값, 화면의 실패 안내를 한 흐름에 함께 적으면 구현 순서를 정하기 쉽습니다.
모델의 의미를 확인하기
어떤 도서의 현재 가격이 35,000원에서 36,000원으로 바뀌었습니다. 이전 주문에 수량 2와 priceAtPurchase: 35000이 남아 있다면 그 주문 금액과 현재 장바구니의 수량 2 금액은 각각 얼마인가요? 가격을 반드시 0 이상의 정수로 저장해야 한다는 정책은 원 Book 스키마에 이미 구현돼 있을까요?
현재 참조와 구매 시점 기록
이전 주문은 구매 가격을 보존해 70,000원이며, 현재 Book 가격을 읽는 장바구니는 72,000원입니다. 금액이 다르다는 이유로 주문의 구매 가격을 현재 가격으로 덮어쓰지 않습니다. 원 Book에는 Number와 required만 있고 가격의 min·정수 검사까지 선언되어 있지 않습니다. 그런 업무 정책이 필요하면 검증과 테스트를 추가해야 합니다.
요구사항 정의 및 기능 목록 작성
프로젝트의 목표를 달성하기 위해 필요한 기능들을 구체적으로 정의합니다.
사용자 관점에서 어떤 기능을 제공해야 하는지 상세하게 나열합니다.
핵심 기능 (MVP)
최소 기능 제품(MVP - Minimum Viable Product)은 프로젝트의 핵심 가치를 전달할 수 있는 최소한의 기능 집합입니다.
MVP를 먼저 개발하여 빠르게 피드백을 받고 점진적으로 기능을 확장합니다.
- 사용자 인증: 장바구니와 주문을 사용자별로 분리하기 위한 로그인, 로그아웃, 서버 세션 확인.
- 도서 목록 조회: 모든 도서 목록을 페이지네이션과 함께 표시.
- 도서 검색: 도서 제목, 저자 등으로 검색.
- 도서 상세 정보: 특정 도서의 상세 정보(제목, 저자, 설명, 가격, 이미지 등) 표시.
- 장바구니 기능: 도서 추가, 수량 변경, 도서 삭제.
- 주문 기능 (가상): 장바구니의 도서를 가상으로 주문 (결제 시스템 연동은 MVP에서 제외).
추가 기능 (향후 확장 고려)
MVP 이후 확장할 수 있는 기능들을 미리 구상해 봅니다.
- 사용자 리뷰 및 평점 시스템.
- 위시리스트 기능.
- 추천 도서 기능 (개인화).
- 관리자 페이지 (도서 추가/수정/삭제, 주문 관리).
- 실제 결제 시스템 연동 (Stripe, Toss Payments 등).
- 국제화 (i18n) 지원.
- 푸시 알림.
기술 스택 선정
Next.js를 기반으로 하지만, 백엔드, 데이터베이스, 스타일링, 배포 등 전반적인 기술 스택을 결정합니다.
프론트엔드 (Next.js 기반)
- 프레임워크: Next.js (React 기반)
- 렌더링: 정적 렌더링(정적인 정보 페이지), 동적 렌더링(검색 결과, 사용자별 장바구니), 클라이언트 컴포넌트(장바구니, 주문, 검색 입력)를 적절히 활용.
- 데이터 페칭:
fetchAPI, 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 · Bookstore request boundaries
북스토어의 화면·서버·저장소
화살표는 브라우저 → Next.js 서버 → MongoDB의 요청·데이터 처리 방향입니다. 세션 확인과 도서·장바구니·주문의 DB 조회·변경은 서버가 맡고, 화면에는 필요한 결과를 전달합니다.
기능의 책임을 나타낸 구조입니다. 정적 자산·캐시 응답은 CDN에서 처리할 수 있고, 렌더링과 Server Action이 별도 서버로 분리된다는 뜻은 아닙니다.
Auth.js는 서버 세션에서 사용자 식별 정보를 제공하고, 장바구니·주문 액션은 이 ID로 조회 대상을 제한합니다. 데이터베이스 연결 문자열과 권한 검사는 서버 경계에 둡니다.
폴더/파일 구조 설계
App Router 기반으로 프로젝트 구조를 설계합니다. 아래 트리에서 # 뒤는 설명이며 실제 파일·폴더 이름에는 포함하지 않습니다.
데이터 모델링
애플리케이션이 다룰 데이터의 구조를 정의합니다.
NoSQL (MongoDB)을 기준으로 예시를 들어보겠습니다.
주요 엔티티 식별
- Book: 도서 정보.
- User: Auth.js 공급자와 세션이 관리하는 사용자 식별 정보. 이 MVP는 별도
User모델을 만들지 않습니다. - CartItem: 장바구니에 담긴 도서 항목.
- Order: 주문 정보.
CartItem은 bookId와 수량을 저장해 도서의 현재 정보와 연결합니다. Order의 각 항목은 bookId와 구매 시점 가격인 priceAtPurchase를 함께 저장하므로, 이후 도서 가격이 바뀌어도 주문 금액을 현재 가격으로 다시 계산하지 않습니다. userId 문자열은 각 장바구니·주문의 소유자를 구분합니다.
스키마 정의 (MongoDB/Mongoose 예시)
각 스키마는 폴더 구조에서 정한 models 파일에 하나씩 분리합니다.
다음 Book 모델은 그대로 복사할 수 있는 예시이며, CartItem과 Order 모델은 다음 절에서 같은 방식으로 구현합니다.
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를 정의하고 이 구조를 실제 화면과 연결합니다.