Guider/Backend/BackendDevGuide0000
Backend#00

BackendDevGuide0000

시리즈 소개

⚙️ 백엔드 개발자 되기 — A-Z 완전 정복 가이드

비전공자도 OK! 음식점 비유로 쉽게 배우는 서버 개발 | 예상 학습 기간: 3~5개월

백엔드(Backend)란? 눈에 보이지 않는 서버 쪽을 만드는 것입니다.
음식점 비유: 손님(프론트엔드)은 메뉴를 보고 주문하고, 주방(백엔드)에서 실제로 음식을 만들고, 재료는 냉장고(데이터베이스)에 보관합니다!
프론트가 "화면"을 만든다면, 백엔드는 "데이터와 로직"을 처리합니다.

백엔드 개발자 커리큘럼 전체 로드맵


🌐 1단계 — 서버와 인터넷의 동작 원리 이해 (1주)

웹 서비스 3계층 아키텍처

서버란? 24시간 365일 켜져 있으면서 요청을 기다리는 컴퓨터입니다.
여러분이 유튜브를 클릭하면 → 구글 서버가 그 요청을 받아 → 영상 데이터를 보내줍니다.
이 과정이 모두 HTTP 프로토콜을 통해 이루어집니다.
// HTTP 요청/응답 기본 구조
// 클라이언트 → 서버
GET /api/users HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJ...token

// 서버 → 클라이언트
HTTP/1.1 200 OK
Content-Type: application/json
{
  "users": [
    { "id": 1, "name": "홍길동", "email": "hong@example.com" }
  ]
}

🟨 2단계 — Node.js 기초 (3~4주)

Node.js란? JavaScript를 브라우저가 아닌 서버에서 실행할 수 있게 해주는 런타임입니다.
프론트엔드에서 JavaScript를 배웠다면, 같은 언어로 백엔드까지 만들 수 있어요!
# Node.js 설치 확인
node --version  # v20.x.x
npm --version   # 10.x.x

# 프로젝트 초기화
mkdir my-server && cd my-server
npm init -y
// server.js — Node.js 내장 http 모듈로 서버 만들기
const http = require('http');

const server = http.createServer((req, res) => {
  console.log('요청 URL:', req.url);
  console.log('요청 메서드:', req.method);
  
  res.writeHead(200, { 'Content-Type': 'application/json; charset=utf-8' });
  res.end(JSON.stringify({ message: '안녕하세요! 첫 번째 서버입니다!' }));
});

server.listen(3000, () => {
  console.log('서버가 3000번 포트에서 실행 중입니다 🚀');
  console.log('브라우저에서 http://localhost:3000 접속해보세요!');
});
📌 Node.js 핵심 개념
CommonJS (require) vs ESM (import) — 모듈 시스템 두 가지
비동기(Async) — Node.js는 싱글 스레드지만 비동기로 수천 명 동시 처리 가능
이벤트 루프 — 요청이 오면 큐에 넣고 순서대로 처리
npm — 전 세계 200만+ 패키지 설치 관리자
// 파일 시스템 (fs) 모듈 — 파일 읽기/쓰기
const fs = require('fs');

// 비동기 방식 (권장)
fs.readFile('./data.json', 'utf-8', (err, data) => {
  if (err) throw err;
  console.log(JSON.parse(data));
});

// Promise 방식 (더 현대적)
const fsPromises = require('fs/promises');
async function readData() {
  const data = await fsPromises.readFile('./data.json', 'utf-8');
  return JSON.parse(data);
}

// path 모듈 — 경로 다루기
const path = require('path');
const filePath = path.join(__dirname, 'data', 'users.json');

⚡ 3단계 — Express.js로 웹 서버 만들기 (2~3주)

Express란? Node.js로 웹 서버를 쉽게 만들 수 있는 미니멀 프레임워크입니다.
순수 Node.js보다 훨씬 간결하게 라우팅, 미들웨어, 에러 처리를 할 수 있습니다.
npm install express cors dotenv
npm install -D nodemon  # 파일 변경 시 자동 재시작
// app.js — Express 기본 구조
const express = require('express');
const cors = require('cors');
require('dotenv').config();

const app = express();

// ===== 미들웨어 설정 =====
app.use(cors());                          // CORS 허용 (프론트엔드와 통신)
app.use(express.json());                  // JSON 요청 body 파싱
app.use(express.urlencoded({ extended: true }));

// ===== 라우터 연결 =====
app.use('/api/users', require('./routes/users'));
app.use('/api/posts', require('./routes/posts'));

// ===== 에러 핸들러 =====
app.use((err, req, res, next) => {
  console.error(err.stack);
  res.status(500).json({ error: '서버 내부 오류가 발생했습니다.' });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => console.log('서버 실행 중 :' + PORT));

module.exports = app;
// routes/users.js — 사용자 라우터
const express = require('express');
const router = express.Router();

// 임시 데이터 (DB 연결 전 테스트용)
let users = [
  { id: 1, name: '홍길동', email: 'hong@example.com' },
  { id: 2, name: '김영희', email: 'kim@example.com' },
];

// GET /api/users — 목록 조회
router.get('/', (req, res) => {
  const { page = 1, limit = 10, search } = req.query;
  let result = users;
  if (search) result = result.filter(u => u.name.includes(search));
  res.json({ data: result, total: result.length });
});

// GET /api/users/:id — 단건 조회
router.get('/:id', (req, res) => {
  const user = users.find(u => u.id === Number(req.params.id));
  if (!user) return res.status(404).json({ error: '사용자를 찾을 수 없습니다.' });
  res.json(user);
});

// POST /api/users — 생성
router.post('/', (req, res) => {
  const { name, email } = req.body;
  if (!name || !email) {
    return res.status(400).json({ error: '이름과 이메일은 필수입니다.' });
  }
  const newUser = { id: Date.now(), name, email };
  users.push(newUser);
  res.status(201).json(newUser);
});

// PUT /api/users/:id — 수정
router.put('/:id', (req, res) => {
  const idx = users.findIndex(u => u.id === Number(req.params.id));
  if (idx === -1) return res.status(404).json({ error: '없음' });
  users[idx] = { ...users[idx], ...req.body };
  res.json(users[idx]);
});

// DELETE /api/users/:id — 삭제
router.delete('/:id', (req, res) => {
  users = users.filter(u => u.id !== Number(req.params.id));
  res.status(204).send();
});

module.exports = router;

🔧 미들웨어 (Middleware) 완전 이해

미들웨어는 요청(Request)이 라우터에 도달하기 전에 거치는 중간 처리 함수입니다.
마치 음식점의 직원들처럼: 손님 맞이 → 주문 받기 → 주방 전달 → 음식 서빙 순서로 처리됩니다.
// 미들웨어 종류와 사용 패턴
const express = require('express');
const app = express();

// 1. 로깅 미들웨어 (모든 요청에 적용)
app.use((req, res, next) => {
  console.log(new Date().toISOString() + ' ' + req.method + ' ' + req.url);
  next(); // 반드시 next() 호출 → 다음 미들웨어로 이동
});

// 2. 인증 미들웨어 (특정 라우터에만)
const authMiddleware = (req, res, next) => {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).json({ error: '토큰이 없습니다.' });
  
  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    req.user = decoded;
    next();
  } catch {
    res.status(401).json({ error: '유효하지 않은 토큰입니다.' });
  }
};

// 보호된 라우트에만 적용
app.get('/api/profile', authMiddleware, (req, res) => {
  res.json({ user: req.user });
});

// 3. 입력 검증 미들웨어 (express-validator 활용)
// npm install express-validator

🌐 4단계 HTTP 메서드 & REST API 설계

HTTP 메서드 및 RESTful API 설계 원칙


🗄️ 5단계 — 데이터베이스 연결 (2~3주)

SQL 핵심 명령어 및 데이터베이스 개념

데이터베이스란? 데이터를 체계적으로 저장하고 빠르게 찾을 수 있는 전자 창고입니다.
엑셀 표(시트)처럼 행(row)과 열(column)로 데이터를 저장하는 것이 관계형 DB(RDBMS)입니다.
# MySQL 설치 및 연결
npm install mysql2 prisma @prisma/client

# Prisma 초기화 (ORM 설정)
npx prisma init
// prisma/schema.prisma — 데이터 모델 정의
generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

model User {
  id        Int      @id @default(autoincrement())
  name      String
  email     String   @unique
  password  String
  role      Role     @default(USER)
  posts     Post[]
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  content   String   @db.Text
  published Boolean  @default(false)
  author    User     @relation(fields: [authorId], references: [id])
  authorId  Int
  createdAt DateTime @default(now())
}

enum Role {
  USER
  ADMIN
}
// db/prisma.js — Prisma 클라이언트 싱글톤
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
module.exports = prisma;

// routes/posts.js — Prisma로 DB 조작
const prisma = require('../db/prisma');

// 게시글 목록 (페이지네이션)
router.get('/', async (req, res) => {
  const { page = 1, limit = 10 } = req.query;
  const skip = (page - 1) * limit;
  
  const [posts, total] = await Promise.all([
    prisma.post.findMany({
      skip: Number(skip),
      take: Number(limit),
      orderBy: { createdAt: 'desc' },
      include: { author: { select: { name: true } } }, // 작성자 이름도 함께
    }),
    prisma.post.count(),
  ]);
  
  res.json({ data: posts, total, page: Number(page), totalPages: Math.ceil(total / limit) });
});

// 게시글 생성
router.post('/', authMiddleware, async (req, res) => {
  const { title, content } = req.body;
  const post = await prisma.post.create({
    data: { title, content, authorId: req.user.userId },
  });
  res.status(201).json(post);
});

// 게시글 수정 (본인만)
router.put('/:id', authMiddleware, async (req, res) => {
  const post = await prisma.post.findUnique({ where: { id: Number(req.params.id) } });
  if (!post) return res.status(404).json({ error: '없음' });
  if (post.authorId !== req.user.userId) return res.status(403).json({ error: '권한 없음' });
  
  const updated = await prisma.post.update({
    where: { id: Number(req.params.id) },
    data: req.body,
  });
  res.json(updated);
});

🔐 6단계 — 인증과 보안 (2~3주)

JWT 인증 흐름도

npm install jsonwebtoken bcryptjs
// routes/auth.js — 회원가입 & 로그인
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const prisma = require('../db/prisma');

// 회원가입
router.post('/register', async (req, res) => {
  const { name, email, password } = req.body;
  
  // 이메일 중복 확인
  const existing = await prisma.user.findUnique({ where: { email } });
  if (existing) return res.status(400).json({ error: '이미 사용 중인 이메일입니다.' });
  
  // 비밀번호 해시화 (절대 평문으로 저장 금지!)
  const hashedPw = await bcrypt.hash(password, 12); // saltRounds: 12
  
  const user = await prisma.user.create({
    data: { name, email, password: hashedPw },
    select: { id: true, name: true, email: true }, // 비밀번호 제외
  });
  
  res.status(201).json({ message: '회원가입 성공', user });
});

// 로그인
router.post('/login', async (req, res) => {
  const { email, password } = req.body;
  
  const user = await prisma.user.findUnique({ where: { email } });
  if (!user) return res.status(401).json({ error: '이메일 또는 비밀번호가 올바르지 않습니다.' });
  
  const isMatch = await bcrypt.compare(password, user.password);
  if (!isMatch) return res.status(401).json({ error: '이메일 또는 비밀번호가 올바르지 않습니다.' });
  
  // Access Token (짧은 수명) + Refresh Token (긴 수명) 패턴
  const accessToken = jwt.sign(
    { userId: user.id, role: user.role },
    process.env.JWT_SECRET,
    { expiresIn: '1h' }
  );
  const refreshToken = jwt.sign(
    { userId: user.id },
    process.env.JWT_REFRESH_SECRET,
    { expiresIn: '7d' }
  );
  
  res.json({ accessToken, refreshToken });
});

module.exports = router;
🔒 보안 필수 체크리스트
• 비밀번호는 bcrypt로 해시화 (절대 평문 저장 금지)
• API 키, 비밀번호는 .env 파일에만 저장 (GitHub에 절대 올리지 않기)
• SQL Injection 방지 — ORM(Prisma) 사용 또는 준비된 쿼리(Prepared Statement)
• HTTPS 사용 — 배포 시 자동 적용 (Railway, Render 등)
• Rate Limiting — 같은 IP에서 과도한 요청 제한 (express-rate-limit)
• CORS 설정 — 허용된 도메인만 접근 가능하도록
// 보안 미들웨어 추가
npm install helmet express-rate-limit
const helmet = require('helmet');
const rateLimit = require('express-rate-limit');

app.use(helmet()); // 보안 HTTP 헤더 설정

// 로그인 API에 Rate Limiting (1분에 5번만)
const loginLimiter = rateLimit({
  windowMs: 60 * 1000, // 1분
  max: 5,
  message: { error: '너무 많은 시도입니다. 잠시 후 다시 시도해주세요.' },
});
app.use('/api/auth/login', loginLimiter);

🚀 7단계 — 서버 배포 완전 가이드

백엔드 배포 플랫폼 비교

# Railway 배포 (가장 쉬운 방법)
# 1. railway.app 접속 → GitHub 로그인
# 2. "New Project" → GitHub 저장소 선택
# 3. 환경변수 설정 (Variables 탭에서 .env 내용 입력)
# 4. 자동 배포 완료! 도메인 생성

# package.json에 start 스크립트 추가 (필수!)
{
  "scripts": {
    "start": "node app.js",
    "dev": "nodemon app.js",
    "db:migrate": "prisma migrate deploy"
  }
}
# .env 파일 (로컬용 — .gitignore에 추가!)
DATABASE_URL="mysql://user:password@localhost:3306/mydb"
JWT_SECRET="your-super-secret-key-at-least-32-chars"
JWT_REFRESH_SECRET="another-secret-key"
PORT=3000
NODE_ENV=development

# Railway 대시보드에도 같은 내용 입력

🎯 8단계 — 실전 프로젝트: 게시판 API 완성

지금까지 배운 모든 것을 합쳐 완전한 게시판 REST API를 만들어봅니다.
회원가입 → 로그인 → 글쓰기 → 조회 → 수정 → 삭제 전체 사이클을 구현합니다.
// 프로젝트 구조 (현업 표준)
my-backend/
├── src/
│   ├── routes/
│   │   ├── auth.js       # 회원가입, 로그인
│   │   ├── users.js      # 사용자 CRUD
│   │   └── posts.js      # 게시글 CRUD
│   ├── middleware/
│   │   ├── auth.js       # JWT 인증 미들웨어
│   │   ├── validate.js   # 입력 검증
│   │   └── upload.js     # 파일 업로드 (multer)
│   ├── db/
│   │   └── prisma.js     # DB 클라이언트
│   └── utils/
│       └── ApiError.js   # 커스텀 에러 클래스
├── prisma/
│   └── schema.prisma
├── .env
├── .gitignore
├── app.js
└── package.json
// Postman으로 API 테스트하기
// 1. 회원가입
POST http://localhost:3000/api/auth/register
Body (JSON): { "name": "홍길동", "email": "hong@e.com", "password": "1234abcd" }

// 2. 로그인 → 토큰 받기
POST http://localhost:3000/api/auth/login
Body: { "email": "hong@e.com", "password": "1234abcd" }
Response: { "accessToken": "eyJ..." }

// 3. 게시글 작성 (토큰 필요)
POST http://localhost:3000/api/posts
Headers: Authorization: Bearer eyJ...
Body: { "title": "첫 번째 게시글", "content": "내용입니다." }

// 4. 게시글 목록 조회
GET http://localhost:3000/api/posts?page=1&limit=5

📚 현업 필수 추가 개념들

① 파일 업로드 (Multer)

npm install multer
const multer = require('multer');
const storage = multer.diskStorage({
  destination: './uploads/',
  filename: (req, file, cb) => {
    cb(null, Date.now() + '-' + file.originalname);
  },
});
const upload = multer({ storage, limits: { fileSize: 5 * 1024 * 1024 } }); // 5MB 제한

router.post('/upload', authMiddleware, upload.single('image'), (req, res) => {
  res.json({ filename: req.file.filename, url: '/uploads/' + req.file.filename });
});

② 이메일 전송 (Nodemailer)

npm install nodemailer
const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
  service: 'gmail',
  auth: { user: process.env.EMAIL, pass: process.env.EMAIL_PASS },
});

async function sendVerificationEmail(to, code) {
  await transporter.sendMail({
    from: '"My App" <noreply@myapp.com>',
    to,
    subject: '이메일 인증 코드',
    html: '

인증 코드: ' + code + '

10분 내에 입력해주세요.

',
  });
}

③ 환경변수 관리

// .env — 절대 GitHub에 올리지 않기!
DATABASE_URL="mysql://..."
JWT_SECRET="..."

// .env.example — 팀원에게 어떤 변수 필요한지 알려주는 파일 (GitHub에 올려도 OK)
DATABASE_URL="mysql://user:password@localhost:3306/dbname"
JWT_SECRET="your-secret-here"
PORT=3000

④ 에러 처리 패턴 (현업 표준)

// utils/ApiError.js
class ApiError extends Error {
  constructor(statusCode, message) {
    super(message);
    this.statusCode = statusCode;
  }
}

// 사용
router.get('/:id', async (req, res, next) => {
  try {
    const user = await prisma.user.findUnique({ where: { id: Number(req.params.id) } });
    if (!user) throw new ApiError(404, '사용자를 찾을 수 없습니다.');
    res.json(user);
  } catch (err) {
    next(err); // 전역 에러 핸들러로 넘기기
  }
});

// 전역 에러 핸들러 (app.js 맨 아래)
app.use((err, req, res, next) => {
  const status = err.statusCode || 500;
  res.status(status).json({ error: err.message || '서버 오류' });
});

✅ 백엔드 학습 체크리스트

✅ 기초 (반드시 마스터)
☐ HTTP 요청/응답 개념 이해
☐ Node.js 설치 및 기본 모듈 사용
☐ Express로 CRUD API 구현
☐ SQL 기본 명령어 (SELECT, INSERT, UPDATE, DELETE)
☐ Prisma ORM으로 DB 연결
☐ JWT 로그인/로그아웃 구현

🚀 심화 (현업 수준)
☐ 미들웨어 직접 작성 (인증, 로깅, 에러 처리)
☐ REST API 설계 원칙 준수
☐ 비밀번호 bcrypt 해시화
☐ 파일 업로드 (Multer)
☐ Rate Limiting, Helmet 보안 설정
☐ Railway/Render로 배포

🏆 실전 미션
☐ 게시판 API (회원가입, 로그인, CRUD)
☐ Postman으로 전체 API 테스트
☐ 프론트엔드(React)와 연결하여 풀스택 앱 완성

🎯 다음 단계

백엔드 기초를 마쳤다면 다음을 추천합니다:
TypeScript — 타입 안전성으로 대규모 프로젝트 관리
NestJS — 현업에서 선호하는 구조화된 Node.js 프레임워크
Docker — 컨테이너로 어디서나 동일하게 실행
Redis — 캐시/세션/실시간 기능
AWS — 클라우드 인프라 (EC2, RDS, S3)
반응형