Files
slot/docs/05-local-dev-setup.md
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

7.2 KiB

Local Development Setup

0. 사전조건

  • macOS / Linux
  • Docker Desktop 실행 중
  • Homebrew (PostgreSQL, pgloader 용)
  • Node.js 20+, pnpm (신규 시스템 작업 시)

1. 원본 PHP 사이트 로컬 가동

# 0) 사전: Docker 데스크톱 실행 / 5432 PostgreSQL 사용 가능 / 33306 미사용
brew install postgresql@17 pgloader
brew services start postgresql@17

# 1) (한 번만) MariaDB 임시 컨테이너 띄우기
docker network create slot-net 2>/dev/null
docker run -d --name slot-mariadb \
  --network slot-net \
  -e MARIADB_ROOT_PASSWORD=rootpass \
  -p 33306:3306 \
  -v slot-mariadb-data:/var/lib/mysql \
  --restart unless-stopped \
  mariadb:10.5 \
  --character-set-server=utf8mb4 \
  --collation-server=utf8mb4_unicode_ci \
  --max-allowed-packet=512M \
  --innodb-buffer-pool-size=1G

# 2) DB dump 복원 (db/inspection2.sql.gz, db/inspection.sql.gz 있어야 함)
docker cp db/inspection2.sql.gz slot-mariadb:/tmp/
docker cp db/inspection.sql.gz  slot-mariadb:/tmp/
docker exec slot-mariadb sh -c "mariadb -uroot -prootpass -e 'CREATE DATABASE inspection2 DEFAULT CHARACTER SET utf8mb4; CREATE DATABASE inspection DEFAULT CHARACTER SET utf8mb4;'"
docker exec slot-mariadb sh -c "gunzip -c /tmp/inspection2.sql.gz | mariadb -uroot -prootpass --default-character-set=utf8mb4 inspection2"
docker exec slot-mariadb sh -c "gunzip -c /tmp/inspection.sql.gz  | mariadb -uroot -prootpass --default-character-set=utf8mb4 inspection"

# 3) PHP + Apache + Redis 컨테이너 가동
cd docker && docker compose up -d

# 첫 실행 시 entrypoint 가 ~5분 정도 걸린다 (apt-get + composer install).
# 진행 상태:  docker logs -f slot-php

# 4) 사이트 접속
open http://localhost:8088/
open http://localhost:8088/adm/   # 관리자 (admin 계정 OTP 필요)

1.1 테스트 계정 (로컬에서만 사용)

원본 dump 의 admin 비밀번호는 알 수 없으므로 로컬 검증용 계정을 만들어 사용:

# PBKDF2 해시 생성
docker exec slot-php php -r '
define("_GNUBOARD_", true);
include_once("/var/www/html/lib/pbkdf2.compat.php");
echo create_hash("test1234"); echo PHP_EOL;'

# 위 출력 해시를 변수에 담아 회원 추가 (level 10 = 일반회원, 12 = 최고관리자)
HASH='<위에서 출력된 해시>'
docker exec slot-mariadb mariadb -uroot -prootpass inspection2 -e "
INSERT IGNORE INTO g5_member 
  (mb_id, mb_password, mb_name, mb_nick, mb_email, mb_level, mb_datetime, mb_today_login, mb_open) 
VALUES 
  ('testlogin', '$HASH', '테스트', '테스트', 'test@local.test', 10, NOW(), NOW(), 1);"

이제 testlogin / test1234 로 로그인 가능. 관리자는 admin 계정 비밀번호를 PBKDF2 해시로 직접 update 후 로그인 (운영 OTP 가 활성화되어 있어 OTP 단계 통과 필요).

2. PostgreSQL 마이그레이션 (재실행)

# 빈 DB 생성
psql -h localhost -d postgres -c "
DROP DATABASE IF EXISTS slot;
CREATE DATABASE slot WITH ENCODING='UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE=template0;
DROP DATABASE IF EXISTS slot_legacy;
CREATE DATABASE slot_legacy WITH ENCODING='UTF8' LC_COLLATE='C' LC_CTYPE='C' TEMPLATE=template0;"

# pgloader 실행
cd db
pgloader migrate_inspection2.load    # ~6분, 165 테이블
pgloader migrate_inspection.load     # ~10초

# 검증
psql -h localhost -d slot -c "
SELECT count(*) AS pg_tables, COALESCE(SUM(reltuples)::bigint,0) AS approx_rows
FROM pg_class c JOIN pg_namespace n ON c.relnamespace=n.oid
WHERE n.nspname='inspection2' AND c.relkind='r';"

3. 운영 서버에서 새 DB dump 가져오기 (옵션)

scripts/refresh-db.sh (예시):

#!/bin/bash
# 1) 원격에서 dump 생성
sshpass -p "$SSH_PASS" ssh -p 21693 root@103.31.14.207 'bash -s' < db/remote_dump.sh
# 2) 로컬로 복사
sshpass -p "$SSH_PASS" rsync -az -e 'ssh -p 21693' root@103.31.14.207:/tmp/slot_dbdump/ db/
# 3) 로컬 MariaDB 로 재복원 (위 1.2 단계 반복)

운영 서버 SSH 패스워드는 환경변수 SSH_PASS 로만 주입하고 저장소에는 두지 말 것.

4. 자주 쓰는 명령

# PHP 컨테이너 셸
docker exec -it slot-php bash

# Apache 에러 로그
docker logs slot-php 2>&1 | grep -iE "error|warn|fatal" | tail -30
# (php_errors.log 는 컨테이너 안 /var/log/apache2/php_errors.log 에 저장됨)
docker exec slot-php tail -f /var/log/apache2/php_errors.log

# MariaDB 셸
docker exec -it slot-mariadb mariadb -uroot -prootpass inspection2

# PostgreSQL 셸
psql -h localhost -d slot
# 데이터는 schema 'inspection2' 안:
#   slot=> SET search_path TO inspection2; SELECT count(*) FROM g5_member;

# Redis 셸
docker exec -it slot-redis redis-cli

# 전체 스택 종료
cd docker && docker compose down

# 전체 스택 재시작 + 재초기화 (entrypoint 다시 실행)
cd docker && docker compose down && docker compose up -d
docker logs -f slot-php

5. 알려진 경고 (정상 동작과 무관)

메시지 원인 해결
Notice: Undefined index HTTP_X_FORWARDED_FOR common.php:2 의 부주의한 헤더 접근 display_errors=Off 로 숨김 (현재 적용됨)
Class 'Redis' not found php-redis 익스텐션 누락 entrypoint 가 pecl install redis 자동 실행
Headers already sent ... display_errors 가 On 이고 PHP notice 출력 display_errors Off (현재 적용됨)
apache2: Could not reliably determine ... ServerName 미설정 (cosmetic) 무시
pdo (pdo.so) is already loaded! Debian 기본 PHP 에 pdo 가 빌트인이라 두 번 로드 무시

6. 운영 서버 / 로컬 차이점 요약

항목 운영 로컬
URL https://slot-ss.com http://localhost:8088
G5_DOMAIN https://slot-ss.com (config.php) env G5_DOMAIN_OVERRIDE
DB 호스트 localhost docker network "slot-net" / slot-mariadb
DB 비밀번호 iiOii5*^^* (운영) rootpass (로컬)
Redis (운영 서버 redis) slot-redis 컨테이너
첨부파일 /var/www/slot-ss.com/data/file/..., data/editor/... 로컬 src/data 는 빈 디렉토리 (실파일 없음)
사용자 업로드 운영 그대로 없음 — 다운받지 않음

7. 트러블슈팅

7.1 컨테이너가 unhealthy 또는 재시작 반복

docker logs slot-php 2>&1 | tail -50
# pecl install redis 가 빌드 의존성 문제로 실패할 수 있음 → entrypoint 가 || true 로 무시
# 그래도 실패 시:
docker exec slot-php bash -lc 'apt-get update && apt-get install -y libssl-dev && pecl install redis && docker-php-ext-enable redis && apache2ctl restart'

7.2 사이트 500

# php_errors.log 확인 (display_errors 는 Off 이므로 화면엔 안 뜸)
docker exec slot-php tail -50 /var/log/apache2/php_errors.log

7.3 DB 연결 실패

# slot-mariadb 가 같은 네트워크에 있는지 확인
docker network inspect slot-net
# 없으면:
docker network connect slot-net slot-mariadb

7.4 포트 충돌

  • 8088 사용 중이면 docker/docker-compose.ymlports: "8088:80" 을 다른 포트로 변경
  • 33306 사용 중이면 위와 마찬가지

8. 신규 시스템 (Next.js) 개발 셋업

(추후 M1 단계에서 추가 예정)

# 모노레포 루트
pnpm install
pnpm db:migrate
pnpm dev   # apps/web (3000) + apps/admin (3001) + apps/api (4000) 동시 실행