283 lines
6.8 KiB
Markdown
283 lines
6.8 KiB
Markdown
# Drizzle ORM 마이그레이션 완료 ✅
|
|
|
|
## 🎉 변경 사항 요약
|
|
|
|
JWT 인증 시스템이 **순수 SQL**에서 **Drizzle ORM**으로 완전히 마이그레이션되었습니다.
|
|
|
|
## 📊 Before & After
|
|
|
|
### Before (순수 SQL)
|
|
```typescript
|
|
// ❌ 타입 안전성 없음
|
|
const user = await db
|
|
.prepare('SELECT id, email, password_hash, nickname FROM users WHERE email = ?')
|
|
.bind(email)
|
|
.first<User>();
|
|
```
|
|
|
|
### After (Drizzle ORM)
|
|
```typescript
|
|
// ✅ 완전한 타입 안전성
|
|
const [user] = await drizzleDb
|
|
.select()
|
|
.from(users)
|
|
.where(eq(users.email, email))
|
|
.limit(1);
|
|
```
|
|
|
|
## 📦 설치된 패키지
|
|
|
|
```json
|
|
{
|
|
"dependencies": {
|
|
"drizzle-orm": "^0.44.7",
|
|
"jose": "^6.1.2"
|
|
},
|
|
"devDependencies": {
|
|
"drizzle-kit": "^0.31.7"
|
|
}
|
|
}
|
|
```
|
|
|
|
## 📁 새로운 파일 구조
|
|
|
|
```
|
|
프로젝트/
|
|
├── drizzle.config.ts # ✨ 신규: Drizzle 설정
|
|
├── drizzle/ # ✨ 신규: 마이그레이션 디렉토리
|
|
│ ├── 0000_omniscient_lady_mastermind.sql
|
|
│ └── meta/
|
|
├── src/
|
|
│ └── lib/
|
|
│ └── server/
|
|
│ ├── schema.ts # ✨ 신규: Drizzle 스키마
|
|
│ ├── db.ts # 🔄 수정: Drizzle 사용
|
|
│ └── auth.ts # 유지
|
|
├── AUTH_GUIDE.md # 🔄 업데이트
|
|
├── DRIZZLE_GUIDE.md # ✨ 신규
|
|
└── package.json # 🔄 스크립트 추가
|
|
```
|
|
|
|
## 🛠️ 새로운 NPM 스크립트
|
|
|
|
```bash
|
|
# Drizzle 마이그레이션 생성
|
|
pnpm db:generate
|
|
|
|
# 로컬 DB에 적용
|
|
pnpm db:push
|
|
|
|
# 프로덕션 DB에 적용
|
|
pnpm db:push:remote
|
|
|
|
# Drizzle Studio 실행
|
|
pnpm db:studio
|
|
|
|
# DB 쿼리 (로컬)
|
|
pnpm db:query
|
|
|
|
# DB 쿼리 (프로덕션)
|
|
pnpm db:query:remote
|
|
```
|
|
|
|
## 🔧 주요 변경 파일
|
|
|
|
### 1. `src/lib/server/schema.ts` (신규)
|
|
Drizzle 스키마 정의:
|
|
```typescript
|
|
import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core';
|
|
import { sql } from 'drizzle-orm';
|
|
|
|
export const users = sqliteTable('users', {
|
|
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
email: text('email').notNull().unique(),
|
|
passwordHash: text('password_hash').notNull(),
|
|
nickname: text('nickname').notNull(),
|
|
createdAt: integer('created_at', { mode: 'timestamp' })
|
|
.notNull()
|
|
.default(sql`(strftime('%s', 'now'))`)
|
|
});
|
|
|
|
export type User = typeof users.$inferSelect;
|
|
export type NewUser = typeof users.$inferInsert;
|
|
```
|
|
|
|
### 2. `src/lib/server/db.ts` (수정)
|
|
Drizzle ORM 사용:
|
|
```typescript
|
|
import { drizzle } from 'drizzle-orm/d1';
|
|
import { eq } from 'drizzle-orm';
|
|
import { users, type User, type NewUser } from './schema';
|
|
|
|
export function getDb(d1: D1Database) {
|
|
return drizzle(d1);
|
|
}
|
|
|
|
export async function getUserByEmail(db: D1Database, email: string) {
|
|
const drizzleDb = getDb(db);
|
|
|
|
const [user] = await drizzleDb
|
|
.select()
|
|
.from(users)
|
|
.where(eq(users.email, email))
|
|
.limit(1);
|
|
|
|
return user || null;
|
|
}
|
|
```
|
|
|
|
### 3. `drizzle.config.ts` (신규)
|
|
Drizzle 설정:
|
|
```typescript
|
|
import { defineConfig } from 'drizzle-kit';
|
|
|
|
export default defineConfig({
|
|
schema: './src/lib/server/schema.ts',
|
|
out: './drizzle',
|
|
dialect: 'sqlite'
|
|
});
|
|
```
|
|
|
|
## ✅ 테스트 완료
|
|
|
|
- [x] Drizzle ORM 설치 완료
|
|
- [x] 스키마 정의 완료
|
|
- [x] 마이그레이션 생성 완료
|
|
- [x] 로컬 DB 적용 완료
|
|
- [x] db.ts Drizzle로 변환 완료
|
|
- [x] TypeScript 빌드 성공
|
|
- [x] 모든 함수 타입 안전성 확보
|
|
|
|
## 🚀 실행 방법
|
|
|
|
### 1. 데이터베이스 초기화
|
|
```bash
|
|
# 이미 완료됨! 마이그레이션이 로컬 DB에 적용되었습니다.
|
|
pnpm db:push # 필요시 재실행
|
|
```
|
|
|
|
### 2. 개발 서버 실행
|
|
```bash
|
|
pnpm cf:dev
|
|
```
|
|
|
|
### 3. 테스트
|
|
- http://localhost:8787/register - 회원가입
|
|
- http://localhost:8787/login - 로그인
|
|
- http://localhost:8787 - 메인 페이지
|
|
|
|
## 🎯 Drizzle ORM의 이점
|
|
|
|
### 1. **타입 안전성**
|
|
```typescript
|
|
// 컴파일 타임에 에러 발견
|
|
const user = await drizzleDb
|
|
.select()
|
|
.from(users)
|
|
.where(eq(users.emial, email)); // ← 컴파일 에러!
|
|
// ^^^^^ 오타
|
|
```
|
|
|
|
### 2. **자동 완성**
|
|
IDE에서 테이블과 컬럼에 대한 완벽한 자동 완성 지원
|
|
|
|
### 3. **자동 마이그레이션**
|
|
```bash
|
|
# 스키마 변경 후
|
|
pnpm db:generate # SQL 자동 생성
|
|
```
|
|
|
|
### 4. **SQL 인젝션 방지**
|
|
모든 쿼리가 자동으로 파라미터화됨
|
|
|
|
### 5. **리팩토링 용이**
|
|
테이블/컬럼명 변경 시 TypeScript가 모든 사용처를 찾아줌
|
|
|
|
## 📚 문서
|
|
|
|
- **`DRIZZLE_GUIDE.md`** - Drizzle ORM 상세 가이드
|
|
- 스키마 정의 방법
|
|
- 고급 쿼리 예제
|
|
- 마이그레이션 관리
|
|
- Drizzle Studio 사용법
|
|
|
|
- **`AUTH_GUIDE.md`** - JWT 인증 가이드 (Drizzle 반영)
|
|
- 로컬 개발 환경 설정
|
|
- 프로덕션 배포
|
|
- 보안 고려사항
|
|
|
|
- **`IMPLEMENTATION_SUMMARY.md`** - 전체 구현 요약
|
|
|
|
## 🔄 마이그레이션 히스토리
|
|
|
|
```
|
|
drizzle/
|
|
└── 0000_omniscient_lady_mastermind.sql # 초기 users 테이블
|
|
```
|
|
|
|
## 💡 다음 단계 제안
|
|
|
|
이제 Drizzle ORM을 활용하여 쉽게 기능을 확장할 수 있습니다:
|
|
|
|
### 1. 프로필 기능 추가
|
|
```typescript
|
|
export const profiles = sqliteTable('profiles', {
|
|
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
userId: integer('user_id').references(() => users.id),
|
|
avatar: text('avatar'),
|
|
bio: text('bio')
|
|
});
|
|
```
|
|
|
|
### 2. 게시글 시스템
|
|
```typescript
|
|
export const posts = sqliteTable('posts', {
|
|
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
userId: integer('user_id').references(() => users.id),
|
|
title: text('title').notNull(),
|
|
content: text('content').notNull(),
|
|
createdAt: integer('created_at', { mode: 'timestamp' }).notNull()
|
|
});
|
|
```
|
|
|
|
### 3. 댓글 기능
|
|
```typescript
|
|
export const comments = sqliteTable('comments', {
|
|
id: integer('id').primaryKey({ autoIncrement: true }),
|
|
postId: integer('post_id').references(() => posts.id),
|
|
userId: integer('user_id').references(() => users.id),
|
|
content: text('content').notNull()
|
|
});
|
|
```
|
|
|
|
모든 관계가 타입 안전하게 관리됩니다!
|
|
|
|
## 🎊 완료!
|
|
|
|
Drizzle ORM으로의 마이그레이션이 성공적으로 완료되었습니다!
|
|
|
|
- ✅ 타입 안전성 확보
|
|
- ✅ 개발 생산성 향상
|
|
- ✅ 유지보수성 개선
|
|
- ✅ 자동 마이그레이션 시스템 구축
|
|
|
|
이제 다음 명령어로 서버를 실행하세요:
|
|
```bash
|
|
pnpm cf:dev
|
|
```
|
|
|
|
---
|
|
|
|
**생성된 파일:**
|
|
- ✨ `drizzle.config.ts`
|
|
- ✨ `src/lib/server/schema.ts`
|
|
- 🔄 `src/lib/server/db.ts` (Drizzle로 재작성)
|
|
- ✨ `drizzle/0000_omniscient_lady_mastermind.sql`
|
|
- ✨ `DRIZZLE_GUIDE.md`
|
|
- 🔄 `AUTH_GUIDE.md` (업데이트)
|
|
- 🔄 `package.json` (스크립트 추가)
|
|
|
|
**기존 파일 백업:**
|
|
- 📦 `src/lib/server/db-old.ts` (순수 SQL 버전)
|
|
|