wing-ops/docs/INSTALL_GUIDE.md
htlee 13d6ca69e2 refactor(db): DDL 스크립트 현행화 + wing_auth→auth 스키마 문서 전면 수정
- database/schema/ 14개 DDL 파일 신규 생성 (운영 DB pg_dump 기반)
- database/seed/ 14개 초기 데이터 파일 분리
- database/_deprecated/로 구 init.sql, auth_init.sql 이동
- database/README.md 신규 작성 (DB 아키텍처, 설치 절차)
- docs/ 6개 가이드 문서 wing_auth→auth 스키마 구조로 수정
- README.md, CLAUDE.md wing 단일 DB 구조 반영

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-01 15:16:38 +09:00

22 KiB
Executable File

WING-OPS 설치 매뉴얼

목차

  1. 시스템 요구사항
  2. 프로젝트 구조
  3. 온라인 설치
  4. 오프라인 설치
  5. DB 초기화 및 마이그레이션
  6. 개발 서버 실행
  7. 운영 서버 배포
  8. CI/CD 자동 배포
  9. 접속 정보 요약
  10. 트러블슈팅

1. 시스템 요구사항

필수 소프트웨어

소프트웨어 최소 버전 권장 버전 용도
Node.js v20 v20 LTS Frontend/Backend 실행
npm v10 v10+ 패키지 관리 (Node.js 포함)
PostgreSQL v15 v16 운영 DB (wing 단일 DB)
PostGIS v3.3 v3.4 공간 데이터 처리
Git v2.30 v2.40+ 소스 코드 관리

하드웨어 권장 사양

항목 개발 환경 운영 환경
CPU 2 Core 4 Core
RAM 4 GB 8 GB
Disk 10 GB 50 GB
OS macOS / Linux / Windows Rocky Linux 9 / CentOS 9

Node.js 설치 (fnm 권장)

fnm(Fast Node Manager)으로 Node.js 버전을 관리한다. 프로젝트 루트의 .node-version 파일에 20이 지정되어 있다.

macOS / Linux:

# fnm 설치
curl -fsSL https://fnm.vercel.app/install | bash

# 셸 재시작 후
fnm install 20
fnm use 20

# 확인
node -v    # v20.x.x
npm -v     # v10.x.x

수동 설치 (fnm 없이):

https://nodejs.org 에서 Node.js 20 LTS를 다운로드하여 설치한다.


2. 프로젝트 구조

wing/
├── frontend/                 React 19 + Vite 7 + TypeScript 5.9 + Tailwind CSS 3
│   ├── src/
│   │   ├── App.tsx           메인 (탭 라우팅, 감사 로그 자동 기록)
│   │   ├── common/           공통 모듈 (@common/ alias)
│   │   │   ├── components/   auth/, layer/, layout/, map/, ui/
│   │   │   ├── hooks/        useLayers, useSubMenu, useAuth
│   │   │   ├── services/     api.ts (Axios), authApi.ts, layerService.ts
│   │   │   ├── store/        authStore, menuStore (Zustand)
│   │   │   ├── types/        backtrack, boomLine, hns, navigation
│   │   │   └── utils/        coordinates, geo, sanitize
│   │   └── tabs/             탭 단위 패키지 (11개)
│   │       ├── prediction/   확산 예측
│   │       ├── hns/          HNS 분석
│   │       ├── rescue/       구조 시나리오
│   │       ├── aerial/       항공 방제
│   │       ├── weather/      해양 기상
│   │       ├── incidents/    사건/사고 관리
│   │       ├── board/        게시판
│   │       ├── reports/      보고서
│   │       ├── assets/       자산 관리
│   │       ├── scat/         Pre-SCAT 조사
│   │       └── admin/        관리자
│   ├── package.json
│   └── vite.config.ts
├── backend/                  Express 4 + TypeScript + PostgreSQL
│   ├── src/
│   │   ├── server.ts         진입점 (보안 미들웨어 + 라우터 등록)
│   │   ├── auth/             인증 (JWT, Google OAuth)
│   │   ├── users/            사용자 관리
│   │   ├── roles/            역할/권한 (RBAC 2차원 권한)
│   │   ├── db/               DB Pool (wingDb, authDb — re-export), seed
│   │   ├── middleware/       보안 (입력 살균, rate-limit)
│   │   └── {도메인}/         도메인별 모듈 (Router + Service)
│   ├── package.json
│   └── tsconfig.json
├── database/                 SQL 스크립트
│   ├── schema/               DDL (스키마 정의)
│   │   ├── 00_init.sql       wing DB 생성, PostGIS, 스키마 설정
│   │   └── 01_auth_tables.sql auth 스키마 테이블 (사용자, 역할, 권한 등)
│   ├── seed/                 초기 데이터 (01~06)
│   ├── migration/            마이그레이션 (001 ~ 016)
│   └── _deprecated/          사용 중단 파일 (auth_init.sql 등)
├── docs/                     개발 문서
├── .githooks/                Git Hooks (pre-commit, commit-msg)
├── .gitea/workflows/         CI/CD (Gitea Actions)
├── .node-version             Node.js 20
└── .npmrc                    npm 레지스트리 (Nexus 프록시)

3. 온라인 설치

인터넷이 가능한 환경에서의 설치 절차.

3-1. 소스 코드 클론

git clone https://gitea.gc-si.dev/gc/wing-ops.git wing
cd wing

3-2. Git Hooks 설정

# pre-commit (TypeScript + ESLint 검증), commit-msg (Conventional Commits 검증)
git config core.hooksPath .githooks
chmod +x .githooks/pre-commit .githooks/commit-msg

3-3. 의존성 설치

npm 레지스트리는 프로젝트 루트의 .npmrc에 Nexus 프록시로 설정되어 있다.

# Frontend
cd frontend
npm install

# Backend
cd ../backend
npm install

3-4. 환경변수 설정

Backend (backend/.env)

# ===========================================
# 서버 설정
# ===========================================
PORT=3001
NODE_ENV=development

# ===========================================
# wing DB (운영 데이터 - PostgreSQL + PostGIS)
# ===========================================
WING_DB_HOST=211.208.115.83
WING_DB_PORT=5432
WING_DB_USER=wing
WING_DB_PASS=<비밀번호>
WING_DB_NAME=wing

# ===========================================
# JWT 인증
# ===========================================
JWT_SECRET=<랜덤 시크릿 문자열>
JWT_EXPIRES_IN=24h

# ===========================================
# CORS (프론트엔드 출처)
# ===========================================
FRONTEND_URL=http://localhost:5173

# ===========================================
# Google OAuth (선택)
# ===========================================
GOOGLE_CLIENT_ID=<Google OAuth 클라이언트 ID>

Frontend (frontend/.env)

# 백엔드 API URL
VITE_API_URL=http://localhost:3001/api

# Google OAuth (선택)
VITE_GOOGLE_CLIENT_ID=<Google OAuth 클라이언트 ID>

# 공공데이터 API 키 (해양기상, 선택)
VITE_DATA_GO_KR_API_KEY=<data.go.kr API 키>
VITE_WEATHER_API_KEY=<기상 API 키>

.env 파일은 .gitignore에 포함된다. 실제 값은 팀 내부에서 공유한다.

3-5. 실행

# 터미널 1: 백엔드
cd backend
npm run dev
# 출력: 서버가 포트 3001에서 실행 중입니다.

# 터미널 2: 프론트엔드
cd frontend
npm run dev
# 출력: VITE vX.X.X ready in XXXms
#        -> Local: http://localhost:5173/

브라우저에서 http://localhost:5173 접속하여 확인한다.


4. 오프라인 설치

인터넷이 불가능한 폐쇄망 환경에서의 설치 절차.

4-1. 온라인 환경에서 패키지 준비

인터넷이 되는 PC에서 다음을 실행한다:

# 1. 프로젝트 클론 및 의존성 설치
git clone https://gitea.gc-si.dev/gc/wing-ops.git wing
cd wing/frontend && npm install
cd ../backend && npm install

# 2. 전체 프로젝트 압축 (node_modules 포함)
cd ../..
tar -czf wing_full.tar.gz wing/

4-2. Node.js 오프라인 설치 파일 준비

대상 OS에 맞는 설치 파일을 다운로드한다:

OS 파일 다운로드
Linux (x64) node-v20.x.x-linux-x64.tar.xz https://nodejs.org/dist/v20.x.x/
macOS (arm64) node-v20.x.x-darwin-arm64.tar.gz https://nodejs.org/dist/v20.x.x/
macOS (x64) node-v20.x.x-darwin-x64.tar.gz https://nodejs.org/dist/v20.x.x/
Windows node-v20.x.x-x64.msi https://nodejs.org/dist/v20.x.x/

4-3. 대상 서버에 설치

# 1. Node.js 설치 (Linux 예시)
tar -xJf node-v20.x.x-linux-x64.tar.xz
export PATH=$PWD/node-v20.x.x-linux-x64/bin:$PATH
# .bashrc 또는 .profile에 PATH 영구 등록

# 2. 프로젝트 압축 해제
tar -xzf wing_full.tar.gz
cd wing

# 3. 환경변수 설정 (3-4 참조)
vi backend/.env
vi frontend/.env

# 4. 실행 (node_modules가 이미 포함되어 있으므로 npm install 불필요)
cd backend && npm run dev    # 터미널 1
cd frontend && npm run dev   # 터미널 2

4-4. 오프라인 환경 주의사항

  • npm install 불가하므로 패키지 추가 시 온라인 환경에서 설치 후 재배포해야 한다.
  • DB는 대상 환경에서 접근 가능한 PostgreSQL을 사용해야 한다.
  • 공공데이터 API (기상, 해양) 키가 필요한 기능은 외부 네트워크 접근이 필요하다.

5. DB 초기화 및 마이그레이션

5-1. DB 구성

프로젝트는 단일 PostgreSQL 데이터베이스(wing)에 3개의 스키마를 사용한다:

스키마 용도 주요 테이블
public 운영 데이터 (사고, 예측, 자산 등) PostGIS 확장 포함
auth 인증/권한 (사용자, 역할, 메뉴, 감사로그) AUTH_USER, AUTH_ROLE, AUTH_PERM 등
wing 기타 도메인 테이블 레이어, 시뮬레이션 등

백엔드는 search_path = wing, auth, public으로 접속하므로 스키마 접두사 없이 테이블을 참조할 수 있다.

5-2. 신규 DB 초기화

PostgreSQL에 최초 설치 시 아래 순서로 실행한다.

# 1. wing DB 및 스키마 초기화 (PostgreSQL superuser로 실행)
psql -U postgres -f database/schema/00_init.sql

# 2. auth 스키마 테이블 생성
psql -U postgres -d wing -f database/schema/01_auth_tables.sql

# 3. 초기 데이터 적재 (01~06 순서대로)
psql -U postgres -d wing -f database/seed/01_common_code.sql
psql -U postgres -d wing -f database/seed/02_org.sql
psql -U postgres -d wing -f database/seed/03_role.sql
psql -U postgres -d wing -f database/seed/04_perm_tree.sql
psql -U postgres -d wing -f database/seed/05_menu.sql
psql -U postgres -d wing -f database/seed/06_admin_user.sql

database/schema/00_init.sql에 포함된 내용:

  • 사용자(wing) 및 데이터베이스(wing) 생성
  • PostGIS, uuid-ossp, pgcrypto 확장 설치
  • public, auth, wing 스키마 생성 및 search_path 설정
  • 공통코드, 시뮬레이션, 사고, 예측 등 핵심 테이블 생성

database/schema/01_auth_tables.sql에 포함된 내용:

  • auth 스키마 내 조직, 역할, 사용자, 권한, 메뉴, 설정, 감사로그 테이블 생성

5-3. 마이그레이션 적용

초기 스키마 이후 추가된 변경 사항은 database/migration/ 디렉토리에 순번대로 관리된다.

database/migration/
├── 001_layer_table.sql         레이어 테이블
├── 002_hns_substance.sql       HNS 물질 데이터
├── 003_perm_tree.sql           권한 트리
├── 004_oper_cd.sql             오퍼레이션 코드
├── 005_db_consolidation.sql    DB 통합
├── 006_board.sql               게시판
├── 007_reports.sql             보고서
├── 008_assets.sql              자산
├── 008_assets_seed.sql         자산 시드 데이터
├── 009_incidents.sql           사건/사고
├── 010_postgis_geom.sql        PostGIS 지오메트리
├── 011_scat.sql                SCAT 조사
├── 012_board_ext.sql           게시판 확장
├── 013_hns_analysis.sql        HNS 분석
├── 014_prediction.sql          확산 예측
├── 015_aerial.sql              항공 방제
└── 016_rescue.sql              구조 시나리오

마이그레이션 실행 (수동):

# wing DB에 순번대로 적용
psql -h <호스트> -p 5432 -U wing -d wing -f database/migration/001_layer_table.sql
psql -h <호스트> -p 5432 -U wing -d wing -f database/migration/002_hns_substance.sql
# ... 순번대로 계속

이미 적용된 마이그레이션을 다시 실행해도 대부분 IF NOT EXISTS 조건이 포함되어 있어 안전하다.

5-4. 시드 데이터

초기 데이터(관리자 계정, 공통코드 등)를 입력한다:

cd backend
npm run db:seed

6. 개발 서버 실행

6-1. 명령어 요약

Frontend:

명령어 설명
npm run dev Vite 개발 서버 (localhost:5173, HMR 지원)
npm run build 프로덕션 빌드 (tsc -b && vite build -> dist/)
npm run lint ESLint 검증
npm run preview 빌드 결과 미리보기

Backend:

명령어 설명
npm run dev tsx watch 개발 서버 (localhost:3001, 파일 변경 시 자동 재시작)
npm run build TypeScript 컴파일 (tsc -> dist/)
npm start 프로덕션 실행 (node dist/server.js)
npm run db:seed DB 시드 데이터 입력

6-2. 개발 서버 시작

# 터미널 1: 백엔드 (먼저 실행)
cd backend
npm run dev
# 서버가 포트 3001에서 실행 중입니다.
# wing DB 연결 성공 (211.208.115.83:5432/wing)

# 터미널 2: 프론트엔드
cd frontend
npm run dev
# VITE v7.x.x ready in XXXms
# -> Local: http://localhost:5173/

6-3. 검증 명령어

# TypeScript 타입 체크
cd frontend && npx tsc --noEmit
cd backend && npx tsc --noEmit

# ESLint
cd frontend && npx eslint src/

# Prettier
cd frontend && npx prettier --check src/
cd frontend && npx prettier --write src/    # 자동 수정

7. 운영 서버 배포

7-1. 서버 환경 준비

운영 서버(Rocky Linux 9 기준)에 다음을 설치한다:

# Node.js 20 설치 (fnm 또는 직접 설치)
curl -fsSL https://fnm.vercel.app/install | bash
source ~/.bashrc
fnm install 20
fnm use 20

# PostgreSQL 16 + PostGIS 설치 (dnf 또는 직접 설치)
# 이미 설치된 경우 생략

7-2. 수동 배포 절차

Frontend

cd frontend

# 의존성 설치
npm ci

# 환경변수 설정 (빌드 시 Vite가 주입)
export VITE_API_URL=/api
export VITE_GOOGLE_CLIENT_ID=<클라이언트ID>
export VITE_DATA_GO_KR_API_KEY=<키>
export VITE_WEATHER_API_KEY=<키>

# 프로덕션 빌드
npx vite build

# 빌드 결과를 웹 서버 디렉토리로 복사
cp -r dist/* /deploy/wing-demo/

Backend

cd backend

# 의존성 설치
npm ci

# TypeScript 컴파일
npx tsc

# 프로덕션 의존성만 유지 (devDependencies 제거)
npm prune --omit=dev

# 배포 디렉토리로 복사
mkdir -p /deploy/wing-demo-backend/dist
cp -r dist/* /deploy/wing-demo-backend/dist/
cp -r node_modules /deploy/wing-demo-backend/
cp package.json /deploy/wing-demo-backend/

7-3. systemd 서비스 등록

Backend를 systemd 서비스로 등록하여 자동 시작/재시작을 설정한다.

서비스 파일 생성 (/etc/systemd/system/wing-demo-api.service):

[Unit]
Description=WING-OPS Backend API
After=network.target postgresql.service

[Service]
Type=simple
User=deploy
WorkingDirectory=/deploy/wing-demo-backend
ExecStart=/home/deploy/.local/share/fnm/aliases/default/bin/node dist/server.js
Restart=on-failure
RestartSec=5

# 환경변수
Environment=NODE_ENV=production
Environment=PORT=3001
Environment=WING_DB_HOST=211.208.115.83
Environment=WING_DB_PORT=5432
Environment=WING_DB_USER=wing
Environment=WING_DB_PASS=<비밀번호>
Environment=WING_DB_NAME=wing
Environment=JWT_SECRET=<시크릿>
Environment=JWT_EXPIRES_IN=24h
Environment=FRONTEND_URL=https://wing-demo.gc-si.dev
Environment=GOOGLE_CLIENT_ID=<클라이언트ID>

[Install]
WantedBy=multi-user.target

서비스 등록 및 시작:

sudo systemctl daemon-reload
sudo systemctl enable wing-demo-api
sudo systemctl start wing-demo-api

# 상태 확인
sudo systemctl status wing-demo-api

# 로그 확인
sudo journalctl -u wing-demo-api -f

7-4. 리버스 프록시 (Nginx)

Frontend 정적 파일과 Backend API를 하나의 도메인으로 서비스한다.

server {
    listen 443 ssl;
    server_name wing-demo.gc-si.dev;

    ssl_certificate     /etc/ssl/certs/wing-demo.crt;
    ssl_certificate_key /etc/ssl/private/wing-demo.key;

    # Frontend 정적 파일
    root /deploy/wing-demo;
    index index.html;

    location / {
        try_files $uri $uri/ /index.html;
    }

    # Backend API 프록시
    location /api/ {
        proxy_pass http://127.0.0.1:3001/api/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    # 헬스 체크
    location /health {
        proxy_pass http://127.0.0.1:3001/health;
    }
}

# HTTP -> HTTPS 리다이렉트
server {
    listen 80;
    server_name wing-demo.gc-si.dev;
    return 301 https://$host$request_uri;
}

8. CI/CD 자동 배포

8-1. Gitea Actions 파이프라인

main 브랜치에 push(머지)되면 .gitea/workflows/deploy.yml이 자동 실행된다.

main 브랜치 push
      |
[Checkout]           소스 코드 체크아웃
      |
[Setup Node.js]      Node.js 24 설정
      |
[Configure npm]      Nexus 프록시 레지스트리 설정
      |
[Frontend Build]     npm ci -> vite build -> /deploy/wing-demo/
      |
[Backend Build]      npm ci -> tsc -> npm prune --omit=dev
      |                -> /deploy/wing-demo-backend/
      |
[Deploy Trigger]     .deploy-trigger 파일 생성
                     -> cron/watchdog이 감지 -> 서비스 재시작

8-2. Gitea Secrets 설정

CI/CD에서 사용하는 시크릿을 Gitea에 등록해야 한다:

등록 경로: Settings -> Actions -> Secrets -> Add Secret

Secret 이름 용도
NEXUS_NPM_AUTH npm Nexus 프록시 인증 토큰
GOOGLE_CLIENT_ID Google OAuth 클라이언트 ID
DATA_GO_KR_API_KEY 공공데이터 API 키
WEATHER_API_KEY 기상 API 키

8-3. 배포 확인

# 프론트엔드 응답 확인
curl -s -o /dev/null -w '%{http_code}' https://wing-demo.gc-si.dev/
# 기대: 200

# 백엔드 헬스 체크
curl -s https://wing-demo.gc-si.dev/api/health
# 기대: {"status":"ok"}

# 백엔드 API 정보
curl -s https://wing-demo.gc-si.dev/api/
# 기대: {"name":"WING Backend API","version":"1.0.0","status":"running"}

9. 접속 정보 요약

개발 환경

서비스 URL 포트
Frontend (Vite dev) http://localhost:5173 5173
Backend API http://localhost:3001 3001
Backend 헬스 체크 http://localhost:3001/health 3001
PostgreSQL (wing) 211.208.115.83:5432/wing 5432

운영 환경

서비스 URL
Frontend https://wing-demo.gc-si.dev
Backend API https://wing-demo.gc-si.dev/api/
헬스 체크 https://wing-demo.gc-si.dev/api/health
Gitea https://gitea.gc-si.dev/gc/wing-ops

API 엔드포인트

경로 용도
GET / API 정보
GET /health 헬스 체크
POST /api/auth/login 로그인
POST /api/auth/logout 로그아웃
GET /api/auth/me 현재 사용자
GET /api/users 사용자 목록
GET /api/roles 역할 목록
GET /api/menus 메뉴 목록
GET /api/settings 시스템 설정
GET /api/audit 감사 로그
GET /api/board 게시판
GET /api/layers 레이어
GET /api/simulation 시뮬레이션
GET /api/hns HNS 물질
GET /api/reports 보고서
GET /api/assets 자산
GET /api/incidents 사건/사고
GET /api/scat SCAT 조사
GET /api/prediction 확산 예측
GET /api/aerial 항공 방제
GET /api/rescue 구조 시나리오

10. 트러블슈팅

의존성 설치

증상 원인 해결
npm install 실패 (ENETUNREACH) Nexus 프록시 접근 불가 .npmrc의 registry URL 확인, VPN/네트워크 상태 확인
npm install 실패 (EAUTH) Nexus 인증 토큰 만료 .npmrc_auth 값 갱신
npm install 실패 (peer dependency) 패키지 버전 충돌 npm install --legacy-peer-deps 시도
MODULE_NOT_FOUND node_modules 누락/손상 rm -rf node_modules package-lock.json && npm install

서버 실행

증상 원인 해결
포트 5173/3001 충돌 이미 다른 프로세스가 사용 중 lsof -i :5173 또는 lsof -i :3001로 PID 확인 후 kill -9 <PID>
백엔드 시작 시 DB 연결 실패 DB 접속 정보 오류 또는 네트워크 backend/.env의 DB 호스트/포트/사용자/비밀번호 확인, nc -zv <호스트> 5432로 네트워크 확인
프론트엔드에서 API 호출 CORS 에러 백엔드 CORS 설정 불일치 backend/.envFRONTEND_URL이 프론트엔드 URL과 일치하는지 확인
env: tsx: No such file or directory tsx 미설치 cd backend && npm install 재실행

DB

증상 원인 해결
relation "XXX" does not exist 테이블 미생성 database/schema/*.sql 또는 해당 마이그레이션 SQL 실행
PostGIS 함수 에러 PostGIS 확장 미설치 psql -U postgres -d wing -c "CREATE EXTENSION IF NOT EXISTS postgis"
인코딩 문제 (한글 깨짐) DB 인코딩 설정 DB 생성 시 ENCODING='UTF8' LC_COLLATE='ko_KR.UTF-8' 지정
seed 실패 이미 데이터 존재 또는 FK 제약 에러 메시지 확인 후 해당 테이블 데이터 정리

Git Hooks

증상 원인 해결
pre-commit이 실행되지 않음 hooksPath 미설정 git config core.hooksPath .githooks
pre-commit permission denied 실행 권한 없음 chmod +x .githooks/pre-commit .githooks/commit-msg
TypeScript 에러로 커밋 차단 타입 에러 존재 npx tsc --noEmit으로 에러 확인 후 수정
commit-msg 형식 오류 Conventional Commits 미준수 type(scope): subject 형식 준수 (type: feat, fix, docs 등)

빌드

증상 원인 해결
vite build 메모리 부족 Node.js 힙 메모리 부족 export NODE_OPTIONS=--max-old-space-size=4096 후 재시도
tsc 타입 에러 TypeScript strict 모드 위반 npx tsc --noEmit으로 에러 목록 확인 후 수정
빌드 후 라우팅 404 SPA 서버 설정 누락 Nginx try_files $uri $uri/ /index.html 설정 확인