티스토리 뷰

반응형

SvelteKit으로 시작하는 SSR 백엔드-프론트 기초 100단계

5단계 — MySQL + Prisma 붙이기 (in-memory → 진짜 DB로 교체)

4단계에서 핵심을 제대로 잡았습니다.

UI / routes / SSR 흐름은 그대로
저장소만 교체한다

이번 단계는 그걸 진짜로 증명하는 단계예요.
“DB 붙이면 코드 다 갈아엎는 거 아니야?” → 아닙니다.
서버 저장소 파일 하나만 바꿉니다.


5단계 목표

  • MySQL을 로컬에서 실행한다 (Docker)
  • Prisma로 스키마/마이그레이션을 만든다
  • 4단계의 in-memory 저장소를 DB 저장소로 교체
  • load / actions / UI는 단 한 줄도 안 건드린다

전체 구조 한 눈에 보기

src/
 ├─ routes/
 │   └─ +page.server.ts   (변경 없음)
 │   └─ +page.svelte      (변경 없음)
 │
 └─ lib/
     └─ server/
         ├─ posts.ts      (❌ 제거)
         └─ post.repo.ts  (✅ DB 구현)

Step 5-1. MySQL 실행 (Docker)

가장 안정적인 방법입니다.

docker-compose.yml

version: '3.8'

services:
  mysql:
    image: mysql:8.0
    container_name: sveltekit-mysql
    restart: unless-stopped
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: root
      MYSQL_DATABASE: sveltekit
      MYSQL_USER: app
      MYSQL_PASSWORD: app
    volumes:
      - mysql_data:/var/lib/mysql

volumes:
  mysql_data:

실행:

docker compose up -d

확인:

docker ps

Step 5-2. Prisma 설치 & 초기화

npm install prisma @prisma/client
npx prisma init

.env 수정

DATABASE_URL="mysql://app:app@localhost:3306/sveltekit"

Step 5-3. Prisma 스키마 작성

prisma/schema.prisma

generator client {
  provider = "prisma-client-js"
}

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

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  createdAt DateTime @default(now())
}

마이그레이션 실행:

npx prisma migrate dev --name init

👉 이 시점에 DB 테이블이 실제로 생성됩니다.


Step 5-4. Prisma Client 싱글톤 만들기 (중요)

반응형

개발 서버에서 중복 연결 방지를 위해 필수입니다.

src/lib/server/prisma.ts

import { PrismaClient } from '@prisma/client';

const globalForPrisma = globalThis as unknown as {
	prisma?: PrismaClient;
};

export const prisma =
	globalForPrisma.prisma ??
	new PrismaClient({
		log: ['warn', 'error']
	});

if (process.env.NODE_ENV !== 'production') {
	globalForPrisma.prisma = prisma;
}

Step 5-5. DB 저장소(repository) 구현

👉 여기가 핵심 포인트
4단계의 posts.ts와 인터페이스를 똑같이 유지합니다.

src/lib/server/post.repo.ts

import { prisma } from './prisma';

export type Post = {
	id: number;
	title: string;
	createdAt: Date;
};

export async function getPosts(): Promise<Post[]> {
	return prisma.post.findMany({
		orderBy: { id: 'desc' }
	});
}

export async function addPost(title: string): Promise<Post> {
	return prisma.post.create({
		data: { title }
	});
}

Step 5-6. +page.server.ts에서 import만 교체

이게 전부입니다.

❌ 기존 (4단계)

import { getPosts, addPost } from '$lib/server/posts';

✅ 변경 후

import { getPosts, addPost } from '$lib/server/post.repo';

전체 파일 (실행 가능):

import type { Actions, PageServerLoad } from './$types';
import { fail } from '@sveltejs/kit';
import { getPosts, addPost } from '$lib/server/post.repo';

export const load: PageServerLoad = async () => {
	return {
		posts: await getPosts()
	};
};

export const actions: Actions = {
	default: async ({ request }) => {
		const data = await request.formData();
		const title = String(data.get('title') ?? '').trim();

		if (!title) {
			return fail(400, { error: '제목을 입력해주세요.' });
		}

		await addPost(title);
		return { success: true };
	}
};

👉 UI 코드?
👉 Form Actions?
👉 use:enhance?

전부 그대로입니다.


Step 5-7. 실제 동작 확인 (중요)

1️⃣ 글 추가

  • 입력 → 추가
  • 새로고침 없음
  • DB에 INSERT 발생

2️⃣ 새로고침(F5)

  • 유지됨

3️⃣ 서버 재시작

Ctrl + C
npm run dev
  • 그대로 유지됨

👉 “아… 이게 DB구나”
이 감각이 오면 성공입니다.


이 단계에서 주니어가 꼭 느껴야 할 것

❌ DB = 화면/로직 전체 변경

✅ DB = 저장소 구현체 교체

좋은 구조에서는:

  • UI는 DB를 모른다
  • routes는 DB를 모른다
  • 서버 저장소만 DB를 안다

흔한 실수 TOP 3

❌ Prisma를 routes에서 직접 호출

  • 테스트/교체 어려움
  • 구조 무너짐

❌ 프론트에서 DB 개념 언급

  • SSR 경계 붕괴

❌ “DB 붙였으니까 구조 바꾸자”

  • 이 단계의 핵심을 잃음

오늘 단계에서 반드시 가져가야 할 한 문장

“DB는 백엔드 구조의 ‘핵심’이 아니라
‘교체 가능한 부품’이어야 한다.”

이 감각이 잡히면
이후 인증, 트랜잭션, 권한, 캐시까지
전부 같은 패턴으로 확장됩니다.


 

SvelteKit,SSR,MySQL,Prisma,주니어개발자,백엔드기초,RepositoryPattern,FormActions,풀스택,웹개발

※ 이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함
반응형