From 09ea775a180e92d71c157c1b2f5257b300329604 Mon Sep 17 00:00:00 2001 From: "DESKTOP-TKLFCPR\\ython" Date: Fri, 29 May 2026 18:40:20 +0900 Subject: [PATCH] =?UTF-8?q?fix(setup):=20=EC=84=A4=EC=B9=98=20=EC=8A=A4?= =?UTF-8?q?=ED=81=AC=EB=A6=BD=ED=8A=B8=203=EA=B0=80=EC=A7=80=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=98=88=EB=B0=A9=20=EC=88=98=EC=A0=95=20+=20works?= =?UTF-8?q?pace=20=EC=9E=90=EB=8F=99=EB=B6=84=EC=84=9D=20=EC=9B=8C?= =?UTF-8?q?=ED=81=AC=ED=94=8C=EB=A1=9C=EC=9A=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [설치 스크립트 수정사항] - PYTHONIOENCODING=utf-8 systemd/NSSM 서비스 환경변수 추가 (Windows cp949 오류 예방) - db_init.py 헬퍼 추가: 스키마 불일치 자동 감지 → 백업 → 재초기화 - 포트 8001 충돌 감지 및 기존 프로세스 자동 종료 로직 추가 - --test 검증 항목 강화: HTTP 응답 + 로그인 API + UTF-8 인코딩 포함 - setup_ubuntu/centos/rhel: PYTHONUNBUFFERED=1 추가 [workspace 자동분석 워크플로우] - workspace/ 디렉토리 생성 (소스코드 투입 위치) - .claude/skills/workspace-analyzer/SKILL.md 스킬 생성 Phase 0~6: 탐색→스택탐지→심층분석→리포트→개발환경가이드→하네스생성→CLAUDE.md - CLAUDE.md에 workspace 워크플로우 안내 등록 Co-Authored-By: Claude Sonnet 4.6 --- .claude/skills/workspace-analyzer/SKILL.md | 276 +++++++++++++++++++++ CLAUDE.md | 15 ++ itsm/tools/db_init.py | 116 +++++++++ setup/setup_centos.sh | 22 +- setup/setup_rhel.sh | 22 +- setup/setup_ubuntu.sh | 42 ++-- setup/setup_windows.ps1 | 77 ++++-- workspace/README.md | 45 ++++ 8 files changed, 553 insertions(+), 62 deletions(-) create mode 100644 .claude/skills/workspace-analyzer/SKILL.md create mode 100644 itsm/tools/db_init.py create mode 100644 workspace/README.md diff --git a/.claude/skills/workspace-analyzer/SKILL.md b/.claude/skills/workspace-analyzer/SKILL.md new file mode 100644 index 00000000..3d397f27 --- /dev/null +++ b/.claude/skills/workspace-analyzer/SKILL.md @@ -0,0 +1,276 @@ +--- +name: workspace-analyzer +description: > + 워크스페이스에 소스코드를 넣으면 자동으로 분석·하네스 적용·개발환경 가이드를 제공하는 스킬. + 다음 상황에서 반드시 사용: + (1) "workspace 폴더에 소스 넣었어", "소스 분석해줘", "하네스 적용해줘" 요청; + (2) workspace/ 하위 폴더에 새 프로젝트가 있을 때; + (3) "개발환경 가이드", "이 소스 어떻게 돌려?", "의존성 뭐야?" 질문; + (4) "프로젝트 분석", "코드베이스 파악", "기술스택 알려줘" 요청; + (5) 처음 보는 레포지토리를 분석해야 할 때. + workspace/ 폴더에 소스가 없을 때도 분석 요청이 오면 이 스킬을 먼저 실행하라. +--- + +# Workspace 소스 자동분석 + 하네스 적용 + 개발환경 가이드 + +소스코드를 `workspace/<프로젝트명>/` 에 넣으면 자동으로 3단계를 수행한다. + +--- + +## Phase 0: 워크스페이스 탐색 + +``` +1. Glob("workspace/**") 으로 프로젝트 폴더 목록 확인 +2. 분석 대상 폴더 결정: + - 사용자가 폴더명을 명시한 경우 → 해당 폴더 + - 명시 없으면 가장 최근 수정된 폴더 (수정 시간 기준) + - 폴더가 없으면 → "workspace/<프로젝트명>/ 폴더를 만들고 소스를 넣어주세요." 안내 +``` + +--- + +## Phase 1: 기술스택 자동 탐지 + +아래 파일 존재 여부로 스택을 판별한다. + +| 파일 | 스택 | +|------|------| +| `pom.xml` / `build.gradle` | Java (Maven/Gradle) | +| `package.json` | Node.js / React / Vue / Next.js | +| `requirements.txt` / `pyproject.toml` / `setup.py` | Python | +| `composer.json` | PHP | +| `Gemfile` | Ruby on Rails | +| `go.mod` | Go | +| `Cargo.toml` | Rust | +| `*.csproj` / `*.sln` | .NET / C# | +| `Dockerfile` / `docker-compose.yml` | 컨테이너 | +| `.env.example` / `application.yml` | 설정 파일 | + +**탐지 순서:** +1. Glob으로 루트 파일 목록 확인 +2. 없으면 1~2 depth 하위까지 탐색 +3. 여러 스택 감지 시 → 멀티스택으로 처리 + +--- + +## Phase 2: 심층 분석 (스택별) + +### Java 프로젝트 +``` +필독 파일: pom.xml 또는 build.gradle (의존성), src/main/resources/application*.yml (설정) +분석 항목: + - Spring Boot 버전, JDK 버전 + - 주요 의존성 (JPA, Security, MyBatis, Redis 등) + - DB 설정 (datasource) + - 포트 (server.port, 기본 8080) + - 프로파일 구조 (dev/stg/prd) + - 테스트 프레임워크 (JUnit 5, Mockito) +``` + +### Python 프로젝트 +``` +필독 파일: requirements.txt 또는 pyproject.toml, .env.example +분석 항목: + - FastAPI/Django/Flask/Flask 버전 + - Python 버전 (.python-version, runtime.txt) + - DB ORM (SQLAlchemy, Django ORM, Tortoise) + - 주요 패키지 (celery, redis, boto3 등) + - 실행 진입점 (main.py, app.py, manage.py, wsgi.py) +``` + +### Node.js 프로젝트 +``` +필독 파일: package.json, .env.example, next.config.js +분석 항목: + - 프레임워크 (Next.js, Express, Nest.js, React 순수) + - Node 버전 (.nvmrc, engines 필드) + - 주요 의존성 (ORM, auth, 상태관리 등) + - scripts 명령어 (start, build, dev, test) + - 빌드 도구 (webpack, vite, turbopack) +``` + +### PHP 프로젝트 +``` +필독 파일: composer.json, .env.example +분석 항목: + - 프레임워크 (Laravel, Symfony, CodeIgniter, 순수 PHP) + - PHP 버전 (require 필드) + - DB (Eloquent, Doctrine, mysqli) + - 아티즌 명령어 (Laravel일 때) +``` + +--- + +## Phase 3: 분석 결과 리포트 + +다음 형식으로 사용자에게 보고한다: + +```markdown +## 소스 분석 결과: {프로젝트명} + +### 기술 스택 +- 언어: {언어 및 버전} +- 프레임워크: {프레임워크 및 버전} +- DB: {DB 종류} +- 기타: {주요 라이브러리} + +### 프로젝트 구조 +{핵심 폴더/파일 트리 — 5~10개} + +### 진입점 +- 실행 명령: `{실행 명령어}` +- 기본 포트: {포트번호} +- 설정 파일: `{설정 파일 경로}` +``` + +--- + +## Phase 4: 개발환경 가이드 생성 + +스택에 맞는 설치 명령어와 실행 방법을 단계별로 제공한다. + +### Java (Spring Boot) +```bash +# 1. JDK 설치 확인 +java -version # JDK 17+ 필요 (pom.xml java.version 확인) + +# 2. 빌드 (Maven) +./mvnw clean package -DskipTests + +# 3. DB 설정 (application-local.yml 생성) +# spring.datasource.url, username, password 설정 + +# 4. 실행 +./mvnw spring-boot:run -Dspring-boot.run.profiles=local +# 또는 +java -jar target/{artifact}.jar --spring.profiles.active=local +``` + +### Python (FastAPI/Django) +```bash +# 1. 가상환경 +python3.11 -m venv venv && source venv/bin/activate # Linux/Mac +python -m venv venv && venv\Scripts\activate # Windows + +# 2. 의존성 설치 +pip install -r requirements.txt + +# 3. 환경변수 설정 +cp .env.example .env # .env 편집 후 DB URL, SECRET_KEY 설정 + +# 4. DB 초기화 (있으면) +alembic upgrade head # 또는 python manage.py migrate + +# 5. 실행 +uvicorn main:app --reload --port 8000 # FastAPI +python manage.py runserver 0:8000 # Django +``` + +### Node.js +```bash +# 1. Node.js 버전 확인 (.nvmrc 있으면 nvm use) +node --version + +# 2. 의존성 설치 +npm install # 또는 yarn install / pnpm install + +# 3. 환경변수 +cp .env.example .env + +# 4. DB 마이그레이션 (있으면) +npx prisma migrate dev # Prisma +npm run typeorm:migration:run # TypeORM + +# 5. 실행 +npm run dev # 개발 +npm run build && npm start # 빌드 후 실행 +``` + +--- + +## Phase 5: 하네스 적용 + +프로젝트 유형에 따라 `.claude/` 하네스를 자동 생성한다. + +### 하네스 생성 원칙 +- `workspace/{project}/.claude/agents/` 에 에이전트 생성 +- `workspace/{project}/.claude/skills/` 에 스킬 생성 +- 프레임워크 특성에 맞는 전문 에이전트 구성 + +### Java Spring Boot 하네스 구성 +| 에이전트 | 역할 | +|---------|------| +| `java-dev` | 기능 개발, 테스트 작성 | +| `db-migrator` | 엔티티/마이그레이션 관리 | +| `api-reviewer` | REST API 설계 검토 | + +스킬: `run-tests`, `build-check`, `api-spec` + +### Python FastAPI 하네스 구성 +| 에이전트 | 역할 | +|---------|------| +| `py-dev` | 기능 개발, 의존성 관리 | +| `db-migrator` | Alembic 마이그레이션 | +| `test-runner` | pytest 실행 및 커버리지 | + +스킬: `run-tests`, `lint-check`, `type-check` + +### Node.js 하네스 구성 +| 에이전트 | 역할 | +|---------|------| +| `frontend-dev` | 컴포넌트/페이지 개발 | +| `backend-dev` | API 라우터 개발 | +| `test-runner` | Jest/Vitest 실행 | + +스킬: `lint`, `type-check`, `build-check` + +### 범용 에이전트 (모든 프로젝트 공통) +| 에이전트 | 역할 | +|---------|------| +| `code-reviewer` | PR 리뷰, 보안 검토 | +| `doc-writer` | README, API 문서 생성 | + +--- + +## Phase 6: CLAUDE.md 자동 생성 + +`workspace/{project}/CLAUDE.md` 를 자동 생성한다. 포함 내용: +- 프로젝트 개요 및 기술스택 +- 디렉토리 구조 (핵심 경로만) +- 실행 명령어 (개발/빌드/테스트) +- 환경변수 목록 +- 보안 주의사항 (있으면) +- 하네스 트리거 규칙 + +--- + +## 실행 흐름 요약 + +``` +사용자가 소스를 workspace//에 넣음 + ↓ +Phase 0: workspace/ 탐색 + ↓ +Phase 1: 기술스택 파일 탐지 (Glob) + ↓ +Phase 2: 핵심 파일 읽기 (Read) + ↓ +Phase 3: 분석 리포트 출력 + ↓ +Phase 4: 개발환경 가이드 출력 + ↓ +Phase 5: .claude/ 하네스 생성 (에이전트 + 스킬) + ↓ +Phase 6: CLAUDE.md 생성 + ↓ +사용자 확인 → 추가 분석 or 개발 시작 +``` + +--- + +## 주의사항 + +- **보안**: 소스 내 `.env`, `secrets.yml`, 비밀번호 패턴 발견 시 즉시 경고 +- **외부 API 금지**: 분석 중 외부 서비스 호출 금지 (Ollama만 허용) +- **파일 무결성**: workspace/ 소스를 수정하지 않는다 — 분석과 가이드만 +- **대용량 파일**: 10,000줄 이상 파일은 헤더/핵심 섹션만 읽는다 diff --git a/CLAUDE.md b/CLAUDE.md index dcb85566..625d7ece 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -108,6 +108,21 @@ C:\GUARDiA\ --- +## Workspace 소스 분석 워크플로우 + +**사용법:** +1. `C:\GUARDiA\workspace\<프로젝트명>\` 폴더에 소스코드를 넣는다 +2. Claude에게 "workspace에 소스 넣었어" 또는 "분석해줘" 라고 말한다 +3. `workspace-analyzer` 스킬이 자동으로: + - 기술스택 탐지 (Java/Python/Node.js/PHP 등) + - 개발환경 설치 가이드 제공 + - `.claude/` 하네스 자동 생성 (에이전트 + 스킬) + - `CLAUDE.md` 자동 생성 + +**트리거:** `workspace-analyzer` 스킬을 사용하라 — "소스 분석", "workspace", "개발환경 가이드", "하네스 적용" 요청 시. + +--- + ## 하네스: GUARDiA ITSM **목표:** SR 접수·배포·코드리뷰·SLA·인시던트·RCA·보안패치 등 ITSM 운영 전반 자동화 diff --git a/itsm/tools/db_init.py b/itsm/tools/db_init.py new file mode 100644 index 00000000..01b33bc5 --- /dev/null +++ b/itsm/tools/db_init.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python3 +""" +GUARDiA ITSM — DB 초기화 헬퍼 (설치 스크립트용) + +스키마 불일치 감지 시 자동 백업 후 재초기화. +설치·업그레이드 시 setup 스크립트에서 호출한다. + +사용법: + python tools/db_init.py [--force] + --force: 기존 DB 강제 삭제 후 재초기화 (신규 설치) +""" +import asyncio +import os +import shutil +import sys +from datetime import datetime +from pathlib import Path + +# itsm/ 디렉토리를 Python 경로에 추가 +ITSM_DIR = Path(__file__).parent.parent +sys.path.insert(0, str(ITSM_DIR)) +os.chdir(str(ITSM_DIR)) + +# .env 로드 (있으면) +try: + from dotenv import load_dotenv + load_dotenv(".env") +except ImportError: + pass + + +FORCE = "--force" in sys.argv +DB_PATH = Path(os.getenv("DATABASE_URL", "sqlite+aiosqlite:///./guardia_itsm.db") + .replace("sqlite+aiosqlite:///", "").replace("./", "")) + + +def _backup_db(): + if DB_PATH.exists(): + backup = DB_PATH.with_suffix( + f".backup_{datetime.now().strftime('%Y%m%d_%H%M%S')}.db" + ) + shutil.copy2(DB_PATH, backup) + print(f"[BACKUP] {DB_PATH} → {backup}") + return backup + return None + + +async def _verify_schema(max_retries: int = 1) -> bool: + """ + 현재 DB 스키마가 모델과 일치하는지 확인. + 주요 테이블의 컬럼 존재 여부를 점검한다. + """ + from database import SessionLocal + from models import User + from sqlalchemy import select, text + + for attempt in range(max_retries + 1): + try: + async with SessionLocal() as db: + # User 테이블 전체 컬럼 조회 (가장 자주 변경되는 테이블) + await db.execute(select(User).limit(1)) + return True + except Exception as e: + if attempt == 0: + print(f"[SCHEMA] 스키마 불일치 감지: {e}") + return False + return False + + +async def main(): + from database import init_db, engine + from core.seed import seed_all + from database import SessionLocal + + db_is_sqlite = not os.getenv("DATABASE_URL", "").startswith("postgresql") + + # ── 신규 설치 모드 --force ────────────────────────────────────────────── + if FORCE and db_is_sqlite and DB_PATH.exists(): + print("[FORCE] 기존 DB 삭제 후 재초기화...") + _backup_db() + DB_PATH.unlink() + + # ── DB 존재 시 스키마 검증 ────────────────────────────────────────────── + if db_is_sqlite and DB_PATH.exists(): + print(f"[CHECK] 기존 DB 스키마 검증: {DB_PATH}") + schema_ok = await _verify_schema() + if not schema_ok: + print("[MIGRATE] 스키마 불일치 — 백업 후 재초기화합니다.") + _backup_db() + DB_PATH.unlink() + print("[INFO] 새 스키마로 DB를 생성합니다.") + else: + print("[OK] 스키마 정상") + + # ── 테이블 생성 ──────────────────────────────────────────────────────── + try: + await init_db() + print("[OK] DB 테이블 초기화 완료") + except Exception as e: + print(f"[ERROR] DB 초기화 실패: {e}") + sys.exit(1) + + # ── 시드 데이터 삽입 ────────────────────────────────────────────────── + try: + async with SessionLocal() as db: + await seed_all(db) + print("[OK] 시드 데이터 삽입 완료") + except Exception as e: + print(f"[WARN] 시드 데이터 삽입 오류 (무시): {e}") + + await engine.dispose() + print("[OK] DB 초기화 완료") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/setup/setup_centos.sh b/setup/setup_centos.sh index 05aa0c63..0df9af14 100644 --- a/setup/setup_centos.sh +++ b/setup/setup_centos.sh @@ -140,23 +140,25 @@ ENVEOF warn ".env 생성됨 — SECRET_KEY를 변경하세요" fi -# ── 6. DB 초기화 ──────────────────────────────────────────── +# ── 6. DB 초기화 (스키마 불일치 자동 감지·복구) ───────────────────────── echo "" echo "[6/8] DB 초기화..." cd "$GUARDIA_ROOT/itsm" source /opt/guardia/venv/bin/activate -python -c " -import asyncio, sys -sys.path.insert(0, '.') -from dotenv import load_dotenv; load_dotenv('.env') -from database import init_db -asyncio.run(init_db()) -print('DB OK') -" && ok "DB 초기화 완료" + +if ss -tlnp 2>/dev/null | grep -q ':8001'; then + warn "포트 8001 사용 중 — 기존 프로세스 종료..." + fuser -k 8001/tcp 2>/dev/null || true; sleep 2 +fi + +PYTHONIOENCODING=utf-8 python tools/db_init.py --force \ + && ok "DB 초기화 완료" || fail "DB 초기화 실패" # ── 7. systemd 서비스 ─────────────────────────────────────── echo "" echo "[7/8] systemd 서비스..." +systemctl stop guardia-itsm 2>/dev/null || true + cat > /etc/systemd/system/guardia-itsm.service << SVCEOF [Unit] Description=GUARDiA ITSM Server @@ -167,6 +169,8 @@ Type=exec User=nginx WorkingDirectory=$GUARDIA_ROOT/itsm Environment="PATH=/opt/guardia/venv/bin" +Environment="PYTHONIOENCODING=utf-8" +Environment="PYTHONUNBUFFERED=1" EnvironmentFile=$GUARDIA_ROOT/itsm/.env ExecStart=/opt/guardia/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8001 --workers 4 Restart=always diff --git a/setup/setup_rhel.sh b/setup/setup_rhel.sh index 1283849f..b03e0709 100644 --- a/setup/setup_rhel.sh +++ b/setup/setup_rhel.sh @@ -139,23 +139,25 @@ ENVEOF warn ".env 생성됨 — SECRET_KEY 필수 변경: $ENV_FILE" fi -# ── 7. DB 초기화 ──────────────────────────────────────────── +# ── 7. DB 초기화 (스키마 불일치 자동 감지·복구) ───────────────────────── echo "" echo "[7/9] DB 초기화..." cd "$GUARDIA_ROOT/itsm" source /opt/guardia/venv/bin/activate -python -c " -import asyncio, sys -sys.path.insert(0, '.') -from dotenv import load_dotenv; load_dotenv('.env') -from database import init_db -asyncio.run(init_db()) -print('DB OK') -" && ok "DB 초기화 완료" + +if ss -tlnp 2>/dev/null | grep -q ':8001'; then + warn "포트 8001 사용 중 — 기존 프로세스 종료..." + fuser -k 8001/tcp 2>/dev/null || true; sleep 2 +fi + +PYTHONIOENCODING=utf-8 python tools/db_init.py --force \ + && ok "DB 초기화 완료" || fail "DB 초기화 실패" # ── 8. systemd ────────────────────────────────────────────── echo "" echo "[8/9] systemd 서비스..." +systemctl stop guardia-itsm 2>/dev/null || true + cat > /etc/systemd/system/guardia-itsm.service << SVCEOF [Unit] Description=GUARDiA ITSM Server @@ -166,6 +168,8 @@ Type=exec User=nginx WorkingDirectory=$GUARDIA_ROOT/itsm Environment="PATH=/opt/guardia/venv/bin" +Environment="PYTHONIOENCODING=utf-8" +Environment="PYTHONUNBUFFERED=1" EnvironmentFile=$GUARDIA_ROOT/itsm/.env ExecStart=/opt/guardia/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8001 --workers 4 Restart=always diff --git a/setup/setup_ubuntu.sh b/setup/setup_ubuntu.sh index 3fa4b4bb..c00b39e1 100644 --- a/setup/setup_ubuntu.sh +++ b/setup/setup_ubuntu.sh @@ -45,13 +45,15 @@ if [[ "$TEST_MODE" == "--test" ]]; then } fail_cnt() { echo -e "${RED}[FAIL]${NC} $*"; } - check "Python 3.11+" python3.11 --version - check "pip 설치" python3.11 -m pip --version - check "PostgreSQL" pg_isready -q - check "Redis" redis-cli ping - check "GUARDiA 포트 8001" bash -c 'curl -sf http://localhost:8001/api/dashboard/overview -o /dev/null' - check "Nginx 실행" nginx -t - check "systemd 서비스" systemctl is-active guardia-itsm + check "Python 3.11+" python3.11 --version + check "pip 설치" python3.11 -m pip --version + check "PostgreSQL" pg_isready -q + check "Redis" redis-cli ping + check "GUARDiA 서버 기동" systemctl is-active guardia-itsm + check "GUARDiA HTTP 응답" bash -c 'curl -sf http://localhost:8001/ -o /dev/null' + check "GUARDiA 로그인 API" bash -c 'curl -sf -X POST http://localhost:8001/api/auth/login -H "Content-Type: application/json" -d "{\"username\":\"admin\",\"password\":\"1111\"}" -o /dev/null' + check "Nginx 설정" nginx -t + check "Python UTF-8 인코딩" bash -c 'PYTHONIOENCODING=utf-8 python3.11 -c "print(\"OK\")" > /dev/null' echo "" echo "검증 결과: 성공 $PASS / 실패 $FAIL" @@ -130,24 +132,28 @@ else info ".env 파일 이미 존재 — 건너뜀" fi -# ── 5. DB 초기화 ────────────────────────────────────────── +# ── 5. DB 초기화 (스키마 불일치 자동 감지·복구) ───────────────────────── echo "" echo "[5/8] DB 초기화..." cd "$GUARDIA_ROOT/itsm" source /opt/guardia/venv/bin/activate -python -c " -import asyncio, os, sys -sys.path.insert(0, '.') -from dotenv import load_dotenv -load_dotenv('.env') -from database import init_db -asyncio.run(init_db()) -print('DB 초기화 완료') -" && ok "DB 초기화 완료" + +# 포트 8001 기존 프로세스 종료 (업그레이드 시 충돌 방지) +if ss -tlnp 2>/dev/null | grep -q ':8001'; then + warn "포트 8001 사용 중 — 기존 프로세스 종료..." + fuser -k 8001/tcp 2>/dev/null || true + sleep 2 +fi + +PYTHONIOENCODING=utf-8 python tools/db_init.py --force \ + && ok "DB 초기화 완료" || fail "DB 초기화 실패 — 로그를 확인하세요" # ── 6. systemd 서비스 등록 ─────────────────────────────── echo "" echo "[6/8] systemd 서비스 등록..." +# 기존 서비스 중지 (재설치/업그레이드) +systemctl stop guardia-itsm 2>/dev/null || true + cat > /etc/systemd/system/guardia-itsm.service << SVCEOF [Unit] Description=GUARDiA ITSM Server @@ -158,6 +164,8 @@ Type=exec User=www-data WorkingDirectory=$GUARDIA_ROOT/itsm Environment="PATH=/opt/guardia/venv/bin" +Environment="PYTHONIOENCODING=utf-8" +Environment="PYTHONUNBUFFERED=1" EnvironmentFile=$GUARDIA_ROOT/itsm/.env ExecStart=/opt/guardia/venv/bin/uvicorn main:app --host 0.0.0.0 --port 8001 --workers 4 Restart=always diff --git a/setup/setup_windows.ps1 b/setup/setup_windows.ps1 index de83fd02..e8251d68 100644 --- a/setup/setup_windows.ps1 +++ b/setup/setup_windows.ps1 @@ -42,15 +42,30 @@ if ($Test) { } } - Check-Item "Python 3.11+" { python --version 2>&1 | Select-String "3\.(1[1-9]|[2-9]\d)" } - Check-Item "PostgreSQL" { pg_isready -q } - Check-Item "Redis" { redis-cli ping } - Check-Item "GUARDiA 포트 8001" { - $r = Invoke-WebRequest "http://localhost:8001/api/dashboard/overview" -UseBasicParsing -TimeoutSec 5 - if ($r.StatusCode -ne 200) { throw "API 응답 오류" } + Check-Item "Python 3.11+" { python --version 2>&1 | Select-String "3\.(1[1-9]|[2-9]\d)" } + Check-Item "PostgreSQL 응답" { pg_isready -q } + Check-Item "Redis 응답" { redis-cli ping } + Check-Item "NSSM 서비스 등록" { Get-Service "guardia-itsm" -ErrorAction Stop } + Check-Item "GUARDiA 서비스 실행" { + $s = Get-Service "guardia-itsm" + if ($s.Status -ne "Running") { throw "서비스 상태: $($s.Status)" } } - Check-Item "NSSM 서비스" { Get-Service "guardia-itsm" -ErrorAction Stop } - Check-Item "Nginx" { nginx -t 2>&1 } + Check-Item "GUARDiA HTTP 응답" { + $r = Invoke-WebRequest "http://localhost:8001/" -UseBasicParsing -TimeoutSec 10 + if ($r.StatusCode -ne 200) { throw "HTTP $($r.StatusCode)" } + } + Check-Item "GUARDiA 로그인 API" { + $body = '{"username":"admin","password":"1111"}' + $r = Invoke-WebRequest "http://localhost:8001/api/auth/login" -Method POST ` + -ContentType "application/json" -Body $body -UseBasicParsing -TimeoutSec 10 + if ($r.StatusCode -ne 200) { throw "로그인 실패 ($($r.StatusCode))" } + } + Check-Item "Python UTF-8 인코딩" { + $env:PYTHONIOENCODING = "utf-8" + $out = & python -c "print('OK')" 2>&1 + if ("$out" -notmatch "OK") { throw "인코딩 오류: $out" } + } + Check-Item "Nginx 설정" { nginx -t 2>&1 } Write-Host "" Write-Host "검증 결과: 성공 $pass / 실패 $fail" @@ -158,19 +173,26 @@ MESSENGER_OPS_ROOM=ops Write-Warn ".env 생성됨 — SECRET_KEY를 변경하세요: $envFile" } -# ── 6. DB 초기화 ──────────────────────────────────────────── +# ── 6. DB 초기화 (스키마 불일치 자동 감지·복구) ──────────────────────── Write-Host "" Write-Host "[7/8] DB 초기화..." + +# 포트 8001 기존 프로세스 종료 (업그레이드 시 충돌 방지) +$portProc = Get-NetTCPConnection -LocalPort 8001 -State Listen -ErrorAction SilentlyContinue | Select-Object -First 1 +if ($portProc) { + Write-Warn "포트 8001 사용 중 (PID $($portProc.OwningProcess)) — 종료..." + Stop-Process -Id $portProc.OwningProcess -Force -ErrorAction SilentlyContinue + Start-Sleep -Seconds 2 +} + Push-Location "$GuardiaRoot\itsm" -& "$venvPath\Scripts\python.exe" -c @" -import asyncio, sys, os -sys.path.insert(0, '.') -os.chdir(r'$GuardiaRoot\itsm') -from dotenv import load_dotenv; load_dotenv('.env') -from database import init_db -asyncio.run(init_db()) -print('DB OK') -"@ +$env:PYTHONIOENCODING = "utf-8" +$env:PYTHONUNBUFFERED = "1" +$dbResult = & "$venvPath\Scripts\python.exe" tools\db_init.py --force 2>&1 +$dbResult | ForEach-Object { Write-Host " $_" } +if ($LASTEXITCODE -ne 0) { + Write-Fail "DB 초기화 실패 — 로그를 확인하세요" +} Pop-Location Write-OK "DB 초기화 완료" @@ -181,17 +203,18 @@ Write-Host "[8/8] Windows 서비스 등록 (NSSM)..." $uvicorn = "$venvPath\Scripts\uvicorn.exe" $svcName = "guardia-itsm" -# 기존 서비스 제거 후 재등록 -nssm stop $svcName 2>$null -nssm remove $svcName confirm 2>$null +# 기존 서비스 중지 및 제거 (업그레이드) +try { nssm stop $svcName 2>$null; Start-Sleep -Seconds 2 } catch {} +try { nssm remove $svcName confirm 2>$null } catch {} nssm install $svcName $uvicorn -nssm set $svcName AppParameters "main:app --host 0.0.0.0 --port 8001 --workers 4" -nssm set $svcName AppDirectory "$GuardiaRoot\itsm" -nssm set $svcName AppEnvironmentExtra "PATH=$venvPath\Scripts;$env:PATH" -nssm set $svcName Start SERVICE_AUTO_START -nssm set $svcName AppStdout "C:\guardia\logs\guardia-itsm.log" -nssm set $svcName AppStderr "C:\guardia\logs\guardia-itsm-err.log" +nssm set $svcName AppParameters "main:app --host 0.0.0.0 --port 8001 --workers 4" +nssm set $svcName AppDirectory "$GuardiaRoot\itsm" +# PYTHONIOENCODING=utf-8 필수 — Windows 기본 cp949에서 한글 print 오류 방지 +nssm set $svcName AppEnvironmentExtra "PATH=$venvPath\Scripts;$env:PATH PYTHONIOENCODING=utf-8 PYTHONUNBUFFERED=1" +nssm set $svcName Start SERVICE_AUTO_START +nssm set $svcName AppStdout "C:\guardia\logs\guardia-itsm.log" +nssm set $svcName AppStderr "C:\guardia\logs\guardia-itsm-err.log" New-Item -ItemType Directory -Force "C:\guardia\logs" | Out-Null nssm start $svcName diff --git a/workspace/README.md b/workspace/README.md new file mode 100644 index 00000000..e971f0ff --- /dev/null +++ b/workspace/README.md @@ -0,0 +1,45 @@ +# GUARDiA Workspace + +이 폴더에 분석할 프로젝트 소스코드를 넣으세요. + +## 사용 방법 + +1. **소스 배치** + ``` + workspace/ + └── 프로젝트명/ ← 여기에 소스를 넣으세요 + ├── src/ + ├── pom.xml (Java) + ├── requirements.txt (Python) + ├── package.json (Node.js) + └── ... + ``` + +2. **분석 요청** + - `"workspace에 소스 넣었어. 분석해줘."` + - `"<프로젝트명> 소스 분석하고 개발환경 가이드 해줘."` + - `"이 프로젝트에 하네스 적용해줘."` + +3. **자동 수행 내용** + - 기술스택 탐지 (Java/Spring, Python/FastAPI, Node.js, PHP 등) + - 의존성 및 설정 파일 분석 + - 개발환경 설치 단계별 가이드 + - `.claude/` 하네스 자동 생성 (프로젝트에 맞는 에이전트 + 스킬) + - `CLAUDE.md` 자동 생성 + +## 지원 스택 + +| 스택 | 감지 파일 | +|------|---------| +| Java (Spring/Gradle/Maven) | `pom.xml`, `build.gradle` | +| Python (FastAPI/Django/Flask) | `requirements.txt`, `pyproject.toml` | +| Node.js (React/Next.js/Express) | `package.json` | +| PHP (Laravel/Symfony) | `composer.json` | +| Go | `go.mod` | +| .NET / C# | `*.csproj`, `*.sln` | + +## 보안 주의 + +- `.env` 파일에 실제 비밀번호를 포함하지 마세요 +- 고객사 실제 운영 DB 자격증명이 포함된 파일은 배제하세요 +- `.gitignore` 에 workspace/를 추가하는 것을 권장합니다