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

10 KiB

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

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_membermembers
      • g5_board + g5_write_<bo_table>boards + 단일 posts 테이블 + comments 테이블 (write 테이블 분리 구조 폐기)
      • g5_pointpoint_ledger
      • g5_visitvisits (또는 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 외래키

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/*.phppackages/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_feedbackchatbot_*
  • OpenAI 또는 Anthropic API 연동 (apps/api/src/routes/chatbot.ts)

8. 27개 cron → BullMQ 워커

기존 plugin/cron/auto.*rankup.php 27개 + 기타 cron 들을:

// 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)