# NAS 배포 가이드 (UADECK v4) ## 1. 사전 준비 - Ugreen NAS에 Docker(또는 Container Manager) 설치 - 프로젝트를 NAS에 클론 또는 동기화 - `Git LFS`로 이미지 자산 pull 완료 확인 ## 2. 환경변수 설정 ```bash cp .env.example .env ``` | 변수 | 설명 | |---|---| | `JWT_SECRET` | 32자 이상 랜덤 문자열 (필수) | | `ADMIN_EMAIL` | 최초 관리자 이메일 | | `ADMIN_PASSWORD` | 최초 관리자 비밀번호 (8자+) | | `WEB_PORT` | 웹 노출 포트 (기본 `8080`) | | `CORS_ORIGINS` | 옆 프로젝트 도메인 포함, 쉼표 구분 | 예시: ```env JWT_SECRET=your-random-secret-at-least-32-chars ADMIN_EMAIL=admin@uniare.sori.studio ADMIN_PASSWORD=your-secure-password WEB_PORT=8080 CORS_ORIGINS=https://uniare.sori.studio,https://your-other-app.sori.studio,http://localhost:8080,http://localhost:5500,http://127.0.0.1:5500 ``` ## 3. 로컬 테스트 > **한 줄 요약:** 프로젝트 루트에서 `npm start` → 브라우저 **http://localhost:8080** 회원가입·로그인·덱 저장은 **API 서버**가 떠 있어야 합니다. HTML만 Live Server 등으로 열면 저장·로그인이 **405** 로 실패합니다. ### 빠른 시작 (권장) ```bash npm start # 백그라운드 실행 (터미널 점유 안 함) # 브라우저: http://localhost:8080 npm run logs # 로그 보기 (종료: Ctrl+C) npm stop # 서버 종료 ``` | 명령 | 설명 | |---|---| | `npm start` | Docker로 웹+API 백그라운드 기동 (**일상 개발용**) | | `npm stop` | 서버 종료 | | `npm run logs` | API·Nginx 로그 스트리밍 | | `npm run dev` | 포그라운드 실행 (로그 붙어 있음, `Ctrl+C`로 **서버도 종료**) | | `npm run api:dev` | API만 Node로 실행 (Live Server 병행 시) | ### 저장이 안 될 때 1. `curl http://localhost:8080/api/v1/health` → `{"ok":true,...}` 가 나와야 함 2. 안 나오면 `npm start` 다시 실행 3. `npm run dev` 후 `Healthy`에서 멈춘 것처럼 보여도 **정상**이지만, `Ctrl+C`하면 서버가 꺼짐 → **`npm start` 사용 권장** 4. Live Server(`:5500`)로 HTML만 연 경우 → 아래 방법 B 또는 **반드시 `:8080` 사용** ### 방법 A — Docker (`npm start`와 동일) ```bash npm start ``` 브라우저: **http://localhost:8080** (Live Server 포트가 아님) ### 방법 B — API만 로컬 실행 (Live Server / Cursor 미리보기 사용 시) 터미널 1 — API: ```bash cd api && npm install # 최초 1회 cd .. && npm run api:dev ``` 터미널 2 — HTML은 Live Server 등으로 열기 (예: `:5500`) `.env`의 `CORS_ORIGINS`에 Live Server 포트를 추가하세요: ```env CORS_ORIGINS=...,http://localhost:5500,http://127.0.0.1:5500 ``` 확인: ```bash curl http://localhost:3000/api/v1/health # → {"ok":true,"version":"4.0.0"} ``` ### 405 오류가 나올 때 | 원인 | 해결 | |---|---| | API 미실행 | `npm start` (또는 `npm run dev`) | | Live Server로 HTML만 연 경우 | POST `/api/v1/...`가 정적 서버로 가서 405 발생 → 방법 A 또는 B 사용 | | Docker 미기동 | `docker ps`로 `uadeck-api`, `uadeck-web` 확인 | ## 4. Docker 기동 (NAS / 프로덕션) ```bash # 프로덕션 스택 (Nginx + API) docker compose -f docker-compose.prod.yml up -d --build # API만 단독 (기존 웹서버가 정적 파일 서빙 중일 때) docker compose up -d --build ``` 확인: ```bash curl http://localhost:8080/api/v1/health # → {"ok":true,"version":"4.0.0"} ``` ## 5. 기존 리버스 프록시 연동 이미 NAS에서 Nginx Proxy Manager, Traefik, Caddy 등을 쓰는 경우: ### 옵션 A — `uadeck-web` 포트만 프록시 (권장) ``` https://uniare.sori.studio → http://NAS_IP:8080 ``` `uadeck-web` 컨테이너가 `/api/`와 정적 파일을 모두 처리합니다. ### 옵션 B — 기존 정적 호스팅 + API만 Docker 1. `docker compose up -d` (API만, 포트 3000) 2. 기존 웹서버에 `nginx/uadeck.conf` 규칙 추가: ```nginx location ~ ^/d/([A-Za-z0-9]+)$ { return 302 /cardList.html?d=$1; } location /api/ { proxy_pass http://127.0.0.1:3000; # proxy_set_header ... (uadeck.conf 참고) } ``` ## 6. 최초 관리자 로그인 1. `https://uniare.sori.studio/login.html` 접속 2. `.env`의 `ADMIN_EMAIL` 계정으로 로그인 - API 최초 기동 시 해당 이메일이 없으면 `ADMIN_PASSWORD`로 계정이 자동 생성된다. - **이미 `ADMIN_EMAIL`로 회원가입한 경우** API 재시작 시 해당 계정이 `admin`으로 승격된다. (가입 시 설정한 비밀번호 그대로 사용) 3. 프로필 메뉴 → **관리자** → `/admin.html` > 관리자 메뉴가 안 보이면 **로그아웃 후 다시 로그인**하세요. 브라우저에 이전 `role`이 캐시되어 있을 수 있습니다. ## 7. 운영 명령 ```bash # 로그 docker compose -f docker-compose.prod.yml logs -f uadeck-api # 재시작 docker compose -f docker-compose.prod.yml restart # DB 백업 (볼륨 내 SQLite) docker cp uadeck-api:/data/uadeck.db ./backup/uadeck-$(date +%Y%m%d).db ``` ## 8. 카드/이미지 업데이트 `datas/`, `images/`, HTML 파일은 **볼륨 마운트**이므로: 1. Git pull (또는 파일 동기화) 2. **재빌드 불필요** — 브라우저 새로고침만으로 반영 API 컨테이너는 `datas/`를 read-only 마운트하므로 새 시리즈 파일 추가 후 API 재시작만 하면 됩니다: ```bash docker compose -f docker-compose.prod.yml restart uadeck-api ``` ## 9. 트러블슈팅 | 증상 | 확인 | |---|---| | 로그인 안 됨 | `JWT_SECRET` 설정, API health 확인 | | 공유 링크 404 | Nginx `/d/` 리다이렉트 규칙 | | CORS 오류 | `CORS_ORIGINS`에 옆 프로젝트 도메인 추가 | | 덱 카드 메타 누락 | `datas/.js` 존재 여부, API `DATAS_PATH` |