Files
slot/docs/03-migration-plan.md
T
chpark 980d7d905d Add Next.js + PostgreSQL rewrite scaffold with 4-theme system
Stack
- Next.js 15 (App Router) + TypeScript + Drizzle ORM + postgres-js
- Node scrypt for password hashing; PBKDF2 verifier for legacy gnuboard5 hashes
- pnpm workspace monorepo: apps/web + packages/{db,auth,themes,...}

Themes (admin-selectable at /admin/themes)
- basic     : 그누보드 default reproduction (light, blue accent)
- eyoom     : eb4_maga_005 매거진 reproduction (dark, orange accent, ranking sidebar)
- amina     : Aminam Builder reproduction (light, violet gradient, card grid)
- youngcart : 영카트 shop reproduction (red accent, search bar, category nav)

DB
- New schema (12 tables) pushed to PG via drizzle-kit: members, sessions, boards,
  posts, point_ledger, app_settings, bacara_*, lottery_tickets, roulette_spins,
  game_points, board_groups
- Legacy data still readable from inspection2 schema via @slot/db/legacy

Verified end-to-end against the migrated DB on localhost:3000:
- Home renders with active theme tokens injected as CSS variables
- /free lists 442K real posts from inspection2.g5_write_free
- Login (testlogin/test1234) issues session cookie, header switches to
  "테스트님 환영합니다 / 로그아웃"
- Switching app_settings.theme.global from eyoom → amina swaps colors,
  layout, and Korean nav labels site-wide on next request

Migration docs added: 03-migration-plan, 04-theme-architecture,
05-local-dev-setup, 06-feature-inventory.
2026-04-27 18:51:32 +09:00

213 lines
10 KiB
Markdown

# Migration Plan — gnuboard5(PHP) → Next.js + Node.js + PostgreSQL
## 0. 목표
1. 기존 사이트(`slot-ss.com`) 의 **모든 기능을 보존**한 채 stack 을 PHP → Node/Next 로 전면 교체.
2. **테마 시스템을 빌트인** — 운영자가 관리자 화면에서 다음 4종 중 하나를 선택할 수 있어야 함:
- **기본** (그누보드 default 룩앤필 reproduction)
- **이윰빌더** (현재 운영 중인 `eb4_maga_005` 매거진 레이아웃 reproduction)
- **아미나빌더** (그누보드5 의 또 다른 인기 빌더 — Aminam Builder 룩앤필)
- **영카드(YoungCart)** (영카트 쇼핑몰 중심 레이아웃)
3. PostgreSQL 단일 DB. 회원/포인트/게시판/쇼핑/베팅/검수 모두 통합.
4. 운영 가능한 마이그레이션 체크리스트와 롤백 경로 제공.
## 1. 신규 스택
| 레이어 | 기술 | 용도 |
|--------|------|------|
| Web | **Next.js 15** (App Router, RSC) + TypeScript | SSR/ISR 페이지, SEO, 4테마 라우팅 |
| API | **Hono** (Node.js, edge-friendly) — 또는 Next.js Route Handler | REST + WebSocket 핸들러 |
| Auth | **NextAuth.js v5 (Auth.js)** | 세션, 소셜 로그인, 2FA |
| ORM | **Drizzle ORM** | TypeScript 타입 안전, raw SQL 친화 |
| DB | **PostgreSQL 17** | 메인 데이터 |
| Cache | **Redis 7** | 세션, 캐시, 랭킹, rate-limit |
| Queue | **BullMQ** (Redis backed) | 27개 그누보드 cron 대체 |
| Object Storage | **S3 호환** (R2/MinIO/AWS) | 첨부파일·에디터 이미지 (현재 82.5GB) |
| Search | **Meilisearch** (옵션) 또는 PostgreSQL FTS | 게시판/회원 검색 (현재 sphinx 대체) |
| Realtime | **Socket.IO** 또는 Pusher | 바카라/룰렛 실시간, 알림 |
| 결제 | KCP / 이니시스 / LG U+ Node SDK 또는 직접 통신 | 기존 4종 게이트웨이 대응 |
| 본인인증 | OK-Name / iNICert / Naver/Kakao API | 본인인증 |
| Deploy | Docker + (Vercel | Coolify | Self-hosted) | — |
## 2. 모노레포 레이아웃 (pnpm workspace + Turborepo)
```
slot/
├── apps/
│ ├── web/ # Next.js 사용자 사이트
│ ├── admin/ # Next.js 관리자 (별도 호스트 권장)
│ └── api/ # Hono API + WebSocket
├── packages/
│ ├── db/ # Drizzle 스키마, 마이그레이션, 시드
│ ├── auth/ # 인증 헬퍼, PBKDF2 검증, NextAuth 설정
│ ├── themes/ # 4종 테마 — basic/eyoom/amina/youngcart
│ ├── ui/ # 공통 컴포넌트 (Button, Modal, Editor, Pagination, ...)
│ ├── shop/ # 쇼핑몰 도메인 (item, cart, order, payment)
│ ├── games/ # 바카라/룰렛/복권/슬롯 코어 + Swiun API
│ ├── shared/ # 타입, 유틸, validators (zod)
│ └── workers/ # BullMQ 워커 (rank-up, point-dist, sms)
└── ops/
├── docker/ # docker-compose, Dockerfiles
└── pgloader/ # 기존 db/migrate_*.load 이전
```
## 3. URL 호환성
기존 `.htaccess` 가 정의한 라우트는 그대로 유지 (SEO 보존):
| 기존 패턴 | Next.js 라우트 |
|-----------|---------------|
| `/` | `/` |
| `/<bo_table>` | `/[boTable]` |
| `/<bo_table>/<wr_id>` | `/[boTable]/[wrId]` |
| `/group/<gr_id>` | `/group/[grId]` |
| `/page/<pid>` | `/page/[pid]` |
| `/content/<co_id>` | `/content/[coId]` |
| `/mypage/<t>` | `/mypage/[tab]` |
| `/shop/list-<ca_id>` | `/shop/list/[caId]` |
| `/shop/brand-<br_cd>` | `/shop/brand/[brCd]` |
| `/shop/<it_id>` | `/shop/[itId]` |
| `/adm/*` | `/admin/*` (별도 admin 앱) |
| `/bbs/login.php` | `/login` |
| `/bbs/board.php?bo_table=X` | `/[X]` (rewrite) |
기존 PHP URL(`/bbs/board.php?bo_table=free`)에 대해서는 미들웨어에서 새 URL로 301 리다이렉트.
## 4. 데이터 마이그레이션
1. **이미 완료**: MariaDB → PostgreSQL (pgloader, schema=`inspection2`)
2. **다음 단계**:
- `packages/db/schema/*.ts` — Drizzle 스키마를 신규 design 으로 정의
- `g5_member``members`
- `g5_board` + `g5_write_<bo_table>``boards` + 단일 `posts` 테이블 + `comments` 테이블 (write 테이블 분리 구조 폐기)
- `g5_point``point_ledger`
- `g5_visit``visits` (또는 ClickHouse / 시계열 DB 로 분리)
- 게임/베팅/검수/SMS/챗봇 → 각각 도메인 패키지로
- `packages/db/migrate-from-legacy/*.ts` — 운영 데이터를 신규 스키마로 ETL 변환
- 36개 `g5_write_<X>` 테이블을 단일 `posts` 로 union (board_id 컬럼 추가)
- PBKDF2 비밀번호 해시는 그대로 유지 (legacy verifier로 검증, 첫 로그인 시 bcrypt 로 자동 업그레이드)
3. **검증 쿼리**: 기존 vs 신규 row count, sum(mb_point), 활성 회원 수 등 매칭 확인.
## 5. 인증·세션 호환
### 5.1 비밀번호 호환
- 그누보드 PBKDF2 (sha256, 12000 iter, 24-byte salt+hash) 검증을 그대로 구현 (`packages/auth/legacy-pbkdf2.ts`)
- 신규 가입자는 `bcrypt` 또는 `argon2id` 사용
- 기존 회원이 첫 로그인 성공 시: PBKDF2 검증 후 신규 알고리즘으로 rehash (자동 업그레이드)
### 5.2 세션
- NextAuth Database session (PostgreSQL) — Redis 캐시
- `mb_id` 기반 식별자 → 신규 `user_id` (UUID v7) 매핑 테이블 유지
### 5.3 2FA (ask-otp 호환)
- 관리자 admin 계정 OTP 그대로 유지
- TOTP (Google Authenticator) 표준 사용
## 6. 게시판 모델 통합
기존: 게시판마다 `g5_write_<bo_table>` 테이블 분리 (스키마는 동일)
신규: 단일 `posts` 테이블 + `board_id` 외래키
```sql
CREATE TABLE posts (
id UUID PRIMARY KEY,
board_id TEXT NOT NULL REFERENCES boards(slug),
parent_id UUID, -- 댓글이면 부모 글 id
reply_path TEXT, -- gnuboard wr_reply 호환 (중첩 댓글 정렬)
num BIGINT, -- 글 그룹 (정렬용, gnuboard wr_num 호환)
author_id UUID REFERENCES members(id),
author_name TEXT, -- 비회원 글
subject TEXT,
content TEXT,
attachments JSONB, -- file metadata
hit INTEGER DEFAULT 0,
good INTEGER DEFAULT 0,
bad INTEGER DEFAULT 0,
is_comment BOOLEAN DEFAULT FALSE,
is_secret BOOLEAN DEFAULT FALSE,
ip INET,
created_at TIMESTAMPTZ DEFAULT now(),
updated_at TIMESTAMPTZ
);
CREATE INDEX posts_board_idx ON posts (board_id, created_at DESC);
CREATE INDEX posts_board_thread_idx ON posts (board_id, num, reply_path);
CREATE INDEX posts_author_idx ON posts (author_id, created_at DESC);
```
PostgreSQL 의 partial index, partition, JSONB 활용으로 36개 테이블 union 후에도 성능 무리 없음.
초대형 게시판 (`free` 442K rows) 은 **list partition** 으로 분할 가능.
## 7. 슬롯/카지노 도메인
### 7.1 게임 포인트
- `point_ledger` (append-only) — 적립/사용/환전 내역
- 트리거 또는 워커가 회원 잔고 (`members.point_balance`) 갱신
- 운영 DB 의 `g5_point` (594만 행) → 그대로 임포트
### 7.2 슬롯 베팅 (Swiun API 브릿지)
- `apps/api/src/routes/swiun.ts` 가 외부 슬롯사 API 와 통신
- WebSocket 으로 실시간 베팅 결과 푸시
- 기존 `plugin/swiunApi/*.php` 의 로직 1:1 이전
### 7.3 바카라
- 기존 `plugin/bacara/*.php``packages/games/bacara/*`
- 게임 룰: 베팅(Player/Banker/Tie) + 결과 + 정산
- 실시간 페이지: Socket.IO 룸 단위 브로드캐스트
### 7.4 룰렛
- 기존 `roulette/index.php` 의 휠 게임 → React + Framer Motion 으로 재구현
- 회당 1회 무료 + 추가 회전은 포인트 차감
### 7.5 복권
- `g5_write_lottery_ticket` (45,724건) → `lottery_tickets` 테이블
- 응모 → 추첨 (cron) → 당첨자 통보 → 포인트 지급
### 7.6 블랙리스트 / 검수
- `blacklist_table` (193K), `check_table` (359K) → `blacklist`, `inspection_logs`
- 관리자가 ID/IP/회원명 검색 가능
### 7.7 챗봇
- `chatbot_conversations`, `chatbot_feedback``chatbot_*`
- OpenAI 또는 Anthropic API 연동 (`apps/api/src/routes/chatbot.ts`)
## 8. 27개 cron → BullMQ 워커
기존 `plugin/cron/auto.*rankup.php` 27개 + 기타 cron 들을:
```ts
// packages/workers/jobs/rank-update.ts
queue.add('rank.update', { game: 'bacara' }, { repeat: { cron: '*/5 * * * *' } });
queue.add('rank.update', { game: 'slots' }, { repeat: { cron: '*/5 * * * *' } });
// ...
```
## 9. 첨부파일 (총 82.5GB)
- 운영 서버에서 R2/S3 로 일회성 업로드 (rclone)
- 신규 시스템은 처음부터 직접 S3 에 저장
- DB 의 `g5_board_file.bf_file` 경로 → S3 키로 변환
- 마이그레이션 동안 폴백: missing key → 운영 서버 origin 으로 프록시
## 10. 단계별 마일스톤
| 단계 | 산출물 | 검증 |
|------|-------|------|
| **M0** (완료) | 소스 + DB 로컬 사본, PostgreSQL 셋업, 로컬 PHP 정상 가동 | 로그인 OK |
| **M1** (1~2주) | 모노레포 스캐폴딩, Drizzle 스키마, ETL 첫 패스 (members, posts, point), Next.js 기본 셸, 4-테마 토글 | 회원 로그인 (PBKDF2), 자유게시판 list/view |
| **M2** (3~4주) | 게시판 글쓰기·댓글·첨부, 마이페이지, 포인트, 회원 가입/탈퇴, 알림 | 핵심 게시판 동작 |
| **M3** (5~6주) | 슬롯/바카라/룰렛/복권 기능 이전, BullMQ 워커, 챗봇 | 게임 정상 동작 |
| **M4** (7~8주) | 영카트 쇼핑몰, 결제 게이트웨이, SMS, 본인인증, 소셜 로그인 | 주문/결제/SMS 검증 |
| **M5** (9~10주) | 관리자 페이지 (회원/게시판/베팅/룰렛 관리, **테마 선택 UI**) | 관리자 OTP 로그인 + 일상 운영 가능 |
| **M6** (11~12주) | 첨부파일 S3 이전, SEO 검사, 성능 부하 테스트 (k6), 보안 감사 | Lighthouse 90+ / 부하 테스트 통과 |
| **M7** (13주) | 카나리 트래픽 5% → 50% → 100% 절체. DNS cutover. | 라이브 |
## 11. 롤백
- 신규 시스템 cutover 후 **6주간** 기존 PHP 인프라 hot-standby 유지
- DNS TTL 60s → 4시간 단계 상승
- DB는 신규(PostgreSQL) → 구(MariaDB) 역방향 CDC (Debezium 또는 logical replication adapter) — 비상 시 MariaDB 로 1시간 내 복귀 가능
## 12. 보안 사항
- 운영 DB 패스워드 (`iiOii5*^^*`), 토큰 키 (`ac57f676fe741f0ab3471d81dbee3bf1`), 서버 root 패스워드 모두 **신규 시스템 첫 배포 시 회전**
- ENV 변수는 `.env.local` 또는 Doppler / 1Password / AWS Secrets Manager 로 관리
- 결제·본인인증 키는 운영 환경에만 주입
- WAF (Cloudflare) + rate-limit (Hono middleware + Redis)