# 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 라우트 | |-----------|---------------| | `/` | `/` | | `/` | `/[boTable]` | | `//` | `/[boTable]/[wrId]` | | `/group/` | `/group/[grId]` | | `/page/` | `/page/[pid]` | | `/content/` | `/content/[coId]` | | `/mypage/` | `/mypage/[tab]` | | `/shop/list-` | `/shop/list/[caId]` | | `/shop/brand-` | `/shop/brand/[brCd]` | | `/shop/` | `/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_` → `boards` + 단일 `posts` 테이블 + `comments` 테이블 (write 테이블 분리 구조 폐기) - `g5_point` → `point_ledger` - `g5_visit` → `visits` (또는 ClickHouse / 시계열 DB 로 분리) - 게임/베팅/검수/SMS/챗봇 → 각각 도메인 패키지로 - `packages/db/migrate-from-legacy/*.ts` — 운영 데이터를 신규 스키마로 ETL 변환 - 36개 `g5_write_` 테이블을 단일 `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_` 테이블 분리 (스키마는 동일) 신규: 단일 `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)