980d7d905d
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.
195 lines
7.2 KiB
Markdown
195 lines
7.2 KiB
Markdown
# Local Development Setup
|
|
|
|
## 0. 사전조건
|
|
- macOS / Linux
|
|
- **Docker Desktop** 실행 중
|
|
- **Homebrew** (PostgreSQL, pgloader 용)
|
|
- **Node.js 20+**, **pnpm** (신규 시스템 작업 시)
|
|
|
|
## 1. 원본 PHP 사이트 로컬 가동
|
|
|
|
```bash
|
|
# 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 비밀번호는 알 수 없으므로 로컬 검증용 계정을 만들어 사용:
|
|
|
|
```bash
|
|
# 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 마이그레이션 (재실행)
|
|
|
|
```bash
|
|
# 빈 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` (예시):
|
|
|
|
```bash
|
|
#!/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. 자주 쓰는 명령
|
|
|
|
```bash
|
|
# 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 또는 재시작 반복
|
|
```bash
|
|
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
|
|
```bash
|
|
# php_errors.log 확인 (display_errors 는 Off 이므로 화면엔 안 뜸)
|
|
docker exec slot-php tail -50 /var/log/apache2/php_errors.log
|
|
```
|
|
|
|
### 7.3 DB 연결 실패
|
|
```bash
|
|
# slot-mariadb 가 같은 네트워크에 있는지 확인
|
|
docker network inspect slot-net
|
|
# 없으면:
|
|
docker network connect slot-net slot-mariadb
|
|
```
|
|
|
|
### 7.4 포트 충돌
|
|
- 8088 사용 중이면 `docker/docker-compose.yml` 의 `ports: "8088:80"` 을 다른 포트로 변경
|
|
- 33306 사용 중이면 위와 마찬가지
|
|
|
|
## 8. 신규 시스템 (Next.js) 개발 셋업
|
|
(추후 M1 단계에서 추가 예정)
|
|
|
|
```bash
|
|
# 모노레포 루트
|
|
pnpm install
|
|
pnpm db:migrate
|
|
pnpm dev # apps/web (3000) + apps/admin (3001) + apps/api (4000) 동시 실행
|
|
```
|