diff --git a/wbx-spring-core/docs/WBX_Spring_Framework_개발자가이드.pdf b/wbx-spring-core/docs/WBX_Spring_Framework_개발자가이드.pdf index 6e493af..eff1bb2 100644 Binary files a/wbx-spring-core/docs/WBX_Spring_Framework_개발자가이드.pdf and b/wbx-spring-core/docs/WBX_Spring_Framework_개발자가이드.pdf differ diff --git a/wbx-spring-core/docs/WBX_Spring_Framework_설치가이드_OnPremise.pdf b/wbx-spring-core/docs/WBX_Spring_Framework_설치가이드_OnPremise.pdf index 1985089..078b2df 100644 Binary files a/wbx-spring-core/docs/WBX_Spring_Framework_설치가이드_OnPremise.pdf and b/wbx-spring-core/docs/WBX_Spring_Framework_설치가이드_OnPremise.pdf differ diff --git a/wbx-spring-core/docs/regenerate_pdfs.py b/wbx-spring-core/docs/regenerate_pdfs.py new file mode 100644 index 0000000..9650080 --- /dev/null +++ b/wbx-spring-core/docs/regenerate_pdfs.py @@ -0,0 +1,372 @@ +""" +WBX Spring Framework PDF 가이드 재생성 스크립트. +Docker/Redis → Embedded Redis 변경 사항 반영. + +사용법: python regenerate_pdfs.py +""" +import os +import copy +from PyPDF2 import PdfReader, PdfWriter +from fpdf import FPDF + +DOCS_DIR = os.path.dirname(os.path.abspath(__file__)) +FONT_PATH = r"C:\Windows\Fonts\malgun.ttf" +FONT_BOLD_PATH = r"C:\Windows\Fonts\malgunbd.ttf" + + +class KoreanPDF(FPDF): + """Korean-capable PDF with consistent styling.""" + + def __init__(self): + super().__init__() + self.add_font("malgun", "", FONT_PATH) + self.add_font("malgun", "B", FONT_BOLD_PATH) + self.set_auto_page_break(auto=True, margin=20) + + def header_line(self, title): + self.set_font("malgun", "B", 9) + self.set_text_color(100, 100, 100) + self.cell(0, 6, title, ln=True) + self.set_draw_color(30, 60, 120) + self.set_line_width(0.5) + self.line(10, self.get_y(), 200, self.get_y()) + self.ln(4) + + def section_title(self, text): + self.set_font("malgun", "B", 14) + self.set_text_color(30, 60, 120) + self.cell(0, 10, text, ln=True) + self.ln(2) + + def sub_title(self, text): + self.set_font("malgun", "B", 11) + self.set_text_color(40, 40, 40) + self.cell(0, 8, text, ln=True) + self.ln(1) + + def body(self, text): + self.set_font("malgun", "", 10) + self.set_text_color(60, 60, 60) + self.multi_cell(0, 6, text) + self.ln(2) + + def code_block(self, text): + self.set_fill_color(245, 245, 245) + self.set_font("malgun", "", 9) + self.set_text_color(40, 40, 40) + x = self.get_x() + self.set_x(x + 5) + self.multi_cell(180, 5.5, text, fill=True) + self.ln(3) + + def bullet(self, text): + self.set_font("malgun", "", 10) + self.set_text_color(60, 60, 60) + x = self.get_x() + self.set_x(x + 5) + self.cell(5, 6, "\u2022") + self.multi_cell(170, 6, text) + + def note_box(self, text): + self.set_fill_color(255, 248, 220) + self.set_draw_color(200, 180, 100) + self.set_font("malgun", "B", 9) + self.set_text_color(120, 90, 0) + y = self.get_y() + self.rect(12, y, 186, 20, style="DF") + self.set_xy(15, y + 3) + self.multi_cell(180, 5, text) + self.set_y(y + 23) + + def page_number(self): + self.set_y(-15) + self.set_font("malgun", "", 8) + self.set_text_color(150, 150, 150) + self.cell(0, 10, f"- {self.page_no()} -", align="C") + + +def replace_pages(src_path, replacements, out_path): + """Replace specific pages in a PDF with new fpdf2-generated pages. + + replacements: dict of {page_index: fpdf_generation_function} + """ + reader = PdfReader(src_path) + writer = PdfWriter() + + # Generate replacement pages + replacement_pages = {} + for page_idx, gen_func in replacements.items(): + pdf = gen_func() + tmp = os.path.join(DOCS_DIR, f"_tmp_page_{page_idx}.pdf") + pdf.output(tmp) + tmp_reader = PdfReader(tmp) + replacement_pages[page_idx] = tmp_reader.pages[0] + + # Build output + for i, page in enumerate(reader.pages): + if i in replacement_pages: + writer.add_page(replacement_pages[i]) + else: + writer.add_page(page) + + with open(out_path, "wb") as f: + writer.write(f) + + # Cleanup temp files + for page_idx in replacements: + tmp = os.path.join(DOCS_DIR, f"_tmp_page_{page_idx}.pdf") + if os.path.exists(tmp): + os.remove(tmp) + + print(f" [OK] {os.path.basename(out_path)}") + + +# ============================================================ +# 1. 설치가이드_OnPremise.pdf — Page 3 (requirements), Page 9 (Redis) +# ============================================================ + +def onprem_page3(): + """Page 3: 사전 요구사항 - Redis를 선택으로 변경.""" + pdf = KoreanPDF() + pdf.add_page() + pdf.header_line("WBX Spring Framework | On-Premise 설치 가이드") + pdf.section_title("1. 사전 요구사항 \u00b7 서버 사양") + + pdf.sub_title("1-1. 최소 서버 사양") + pdf.body("항목 최소 사양 권장 사양\n" + "OS RHEL 8+ / Ubuntu 22.04+ RHEL 9 / Rocky Linux 9\n" + "CPU 4 vCPU 8 vCPU\n" + "RAM 8 GB 16 GB\n" + "Disk 50 GB SSD 100 GB SSD (RAID)\n" + "Network 1 Gbps 10 Gbps") + + pdf.sub_title("1-2. 필수 소프트웨어") + pdf.body("소프트웨어 버전 용도\n" + "JDK 21 (Temurin LTS) Spring Boot 런타임\n" + "DB Oracle 19c+ 등 애플리케이션 데이터\n" + "Nginx 1.24+ 리버스 프록시, SSL") + + pdf.sub_title("1-2b. 선택 소프트웨어") + pdf.body("소프트웨어 버전 용도\n" + "Redis 7.x 캐시 (미설치 시 Embedded Redis 자동 구동)") + pdf.note_box("NOTE: Redis를 별도 설치하지 않아도 WBX Spring에 내장된 Embedded Redis가\n" + "자동으로 시작됩니다. 운영 환경에서는 성능을 위해 외부 Redis 설치를 권장합니다.") + + pdf.sub_title("1-3. 네트워크 포트") + pdf.body("포트 서비스 접근 범위 비고\n" + "443 HTTPS 외부 Nginx SSL\n" + "80 HTTP 외부->443 리다이렉트\n" + "8080 Spring Boot 내부 Nginx에서만 접근\n" + "8081 wtm-api 내부 WTM 프로젝트\n" + "3306 MySQL 내부 DB 선택에 따라\n" + "5432 PostgreSQL 내부 \n" + "1521 Oracle 내부 \n" + "1433 MSSQL 내부 \n" + "6379 Redis 내부 선택 (Embedded Redis 자동 대체)") + + pdf.page_number() + return pdf + + +def onprem_page9(): + """Page 9: Redis 설치 섹션 재작성.""" + pdf = KoreanPDF() + pdf.add_page() + pdf.header_line("WBX Spring Framework | On-Premise 설치 가이드") + pdf.section_title("5. Redis 설치 (선택)") + + pdf.note_box("WBX Spring Framework에는 Embedded Redis가 내장되어 있어 별도 설치 없이도\n" + "앱이 정상 구동됩니다. 운영 환경에서 높은 성능이 필요한 경우에만 설치하세요.") + + pdf.sub_title("5-1. Embedded Redis (기본 — 설치 불필요)") + pdf.body("앱 시작 시 다음 순서로 자동 동작합니다:") + pdf.bullet("외부 Redis 감지 시 -> 외부 Redis 사용 (운영 환경)") + pdf.bullet("외부 Redis 없음 -> Embedded Redis 자동 시작 (개발/소규모 운영)") + pdf.bullet("Embedded Redis 실패 -> 인메모리 캐시 전환 (최후 안전장치)") + pdf.ln(3) + + pdf.sub_title("5-2. 외부 Redis 설치 (선택 — 대규모 운영 환경 권장)") + pdf.code_block( + "sudo dnf install -y redis\n" + "sudo systemctl enable --now redis\n\n" + "# 보안: bind + password\n" + "sudo sed -i 's/^bind .*/bind 127.0.0.1/' /etc/redis/redis.conf\n" + "echo 'requirepass RedisP@ss123' | sudo tee -a /etc/redis/redis.conf\n" + "sudo systemctl restart redis\n\n" + "# 확인\n" + "redis-cli -a RedisP@ss123 ping # PONG" + ) + + pdf.sub_title("5-3. .env 설정 (외부 Redis 사용 시)") + pdf.code_block( + "SPRING_DATA_REDIS_HOST=127.0.0.1\n" + "# 또는 원격 Redis 서버 주소\n" + "# SPRING_DATA_REDIS_HOST=redis.company.com" + ) + + pdf.page_number() + return pdf + + +# ============================================================ +# 2. 개발자가이드.pdf — Page 3 (사전 준비), Page 4 (Docker Compose) +# ============================================================ + +def dev_page3(): + """Page 3: 개발환경 설정 - Docker/Redis 부분 수정.""" + pdf = KoreanPDF() + pdf.add_page() + pdf.header_line("WBX Spring Framework | 개발자 가이드") + pdf.section_title("Chapter 0. 개발환경 설정 - IDE \u00b7 프로젝트 생성") + + pdf.sub_title("0-1. 사전 준비") + pdf.bullet("JDK 21 설치 (Eclipse Temurin 권장)") + pdf.bullet("Git 설치 (git config user.name / user.email)") + pdf.bullet("Docker Desktop 설치 (선택 - 로컬 DB 컨테이너 사용 시에만)") + pdf.bullet("IDE 설치 (아래 택 1)") + pdf.ln(2) + + pdf.note_box("NOTE: Redis는 Embedded Redis가 앱과 함께 자동 시작되므로 별도 설치가 필요\n" + "없습니다. Docker Desktop도 DB를 직접 설치하면 불필요합니다.") + + pdf.sub_title("온보딩 플로우") + pdf.body("1) JDK 설치 -> 2) IDE 설정 -> 3) DB 준비 -> 4) 프로젝트 생성 -> 5) bootRun -> 6) Swagger 확인") + + pdf.sub_title("0-2. IDE 선택 가이드") + pdf.body("IDE 권장 대상 핵심 장점\n" + "IntelliJ IDEA 메인 개발 Spring Boot 최적, 리팩터링, DB 브라우저\n" + "VS Code 경량/FE 병행 Extension Pack, DevContainer\n" + "Eclipse/STS 무료/레거시 Spring Tool Suite 플러그인") + + pdf.sub_title("0-3. IntelliJ IDEA 필수 설정") + pdf.bullet("플러그인: Spring Boot, Lombok, JPA Buddy, GitToolBox, .env, SonarLint") + pdf.bullet("Annotation Processor 활성화 (Settings > Build > Compiler)") + pdf.bullet("Hot Reload: Build project automatically + Allow auto-make") + pdf.ln(1) + pdf.code_block( + "Run Configuration:\n" + " Main class: kr.co.accura.wbx.spring.WbxSpringCoreApplication\n" + " Env: JWT_SECRET=dev-secret-key" + ) + + pdf.sub_title("0-4. VS Code 필수 설정") + pdf.bullet("Extension: Java Pack, Spring Boot Pack, Lombok, Gradle, REST Client, GitLens") + pdf.bullet(".vscode/settings.json - Lombok, Gradle Wrapper, 포맷터 설정") + pdf.bullet(".vscode/launch.json - Spring Boot 디버깅 프로필 (local, test)") + + pdf.page_number() + return pdf + + +def dev_page4(): + """Page 4: Docker Compose 및 프로젝트 생성 - Redis 부분 수정.""" + pdf = KoreanPDF() + pdf.add_page() + pdf.header_line("WBX Spring Framework | 개발자 가이드") + + pdf.code_block( + '// .vscode/launch.json\n' + '{\n' + ' "type": "java",\n' + ' "name": "App (Local)",\n' + ' "mainClass": "kr.co.accura.wbx.spring.WbxSpringCoreApplication",\n' + ' "env": {"JWT_SECRET": "dev-secret-key"}\n' + '}' + ) + + pdf.sub_title("0-5. Eclipse / STS 설정") + pdf.bullet("Spring Tools 4 플러그인 설치 (Eclipse Marketplace)") + pdf.bullet("Lombok 설치: java -jar lombok.jar -> Eclipse 경로 선택") + pdf.bullet("Gradle Import: File > Import > Existing Gradle Project") + pdf.bullet("Annotation Processor: Project Properties > Java Compiler 에서 활성화") + pdf.ln(2) + + pdf.sub_title("0-6. 프로젝트 생성 (3가지 방법)") + pdf.body("방법 A: Spring Initializr (start.spring.io)") + pdf.code_block("Project: Gradle-Kotlin | Java: 21 | Boot: 3.5.0\n" + "Group: kr.co.accura | Artifact: {앱}-api\n" + "-> Generate -> 압축 해제 -> wbx-spring-starter 의존성 추가") + pdf.body("방법 B: Git Template Repository") + pdf.code_block("git clone https://git.wbx.kr/accura/wbx-spring-template.git my-app\n" + "cd my-app && ./init.sh --name my-app --group kr.co.accura") + + pdf.sub_title("0-7. 설치 스크립트 (권장)") + pdf.body("프로젝트에 포함된 설치 스크립트가 JDK 자동 설치, Git 사전 검사, 빌드, .env 템플릿 생성을 자동 처리합니다.") + pdf.code_block("# Windows\nscripts\\install.bat\n\n# Linux/macOS\nchmod +x scripts/install.sh && ./scripts/install.sh") + pdf.body("TIP: JDK 미설치 시 스크립트가 자동으로 설치합니다.") + + pdf.sub_title("0-8. 로컬 개발 인프라") + pdf.body("Redis는 Embedded Redis가 앱 시작 시 자동 구동되므로 별도 설치가 필요 없습니다.\n" + "DB만 Docker Compose 또는 직접 설치하면 됩니다.") + pdf.code_block("# Docker로 DB만 시작 (Redis 불필요)\n" + "docker compose -f docker-compose-dev.yml up -d mysql\n\n" + "# 또는 DB를 직접 설치한 경우 바로 앱 실행\n" + "gradlew.bat bootRun") + pdf.note_box("Embedded Redis 동작: 앱 시작 시 외부 Redis 감지 -> 없으면 자동 시작 -> 실패 시 인메모리 캐시") + + pdf.page_number() + return pdf + + +def dev_page5(): + """Page 5: DevContainer + 코드 품질 도구 - Redis 부분 수정.""" + pdf = KoreanPDF() + pdf.add_page() + pdf.header_line("WBX Spring Framework | 개발자 가이드") + + pdf.sub_title("0-9. DevContainer (VS Code)") + pdf.body("devcontainer.json 으로 JDK 21 + DB가 포함된 완전한 개발 환경을 컨테이너로 제공합니다.\n" + "Redis는 Embedded Redis가 자동 구동되므로 DevContainer에 별도 포함하지 않아도 됩니다.\n" + "팀원 전체 동일 환경 보장.") + + pdf.sub_title("0-10. 코드 품질 도구") + pdf.bullet("Spotless - 코드 포맷 자동화 (./gradlew spotlessApply)") + pdf.bullet("CheckStyle - 코드 규칙 검사") + pdf.bullet("JaCoCo - 테스트 커버리지 (최소 70%)") + pdf.bullet("SonarLint - IDE 실시간 코드 분석") + pdf.bullet(".editorconfig - IDE 공통 코드 스타일 (UTF-8, LF, 4 spaces)") + + pdf.page_number() + return pdf + + +# ============================================================ +# Main +# ============================================================ + +def main(): + print("WBX Spring Framework PDF 가이드 재생성") + print("=" * 50) + + # 1. 설치가이드_OnPremise.pdf + print("\n[1] 설치가이드_OnPremise.pdf") + src = os.path.join(DOCS_DIR, "WBX_Spring_Framework_설치가이드_OnPremise.pdf") + out = os.path.join(DOCS_DIR, "WBX_Spring_Framework_설치가이드_OnPremise.pdf") + replace_pages(src, { + 2: onprem_page3, # Page 3: 사전 요구사항 (Redis 선택으로) + 8: onprem_page9, # Page 9: Redis 설치 (Embedded Redis 안내) + }, out) + + # 2. 설치가이드_Cloud.pdf — 변경 없음 (클라우드 관리형 Redis 사용) + print("\n[2] 설치가이드_Cloud.pdf") + print(" [SKIP] 클라우드 환경은 관리형 Redis(Azure Cache/ElastiCache) 사용 - 변경 불필요") + + # 3. 개발자가이드.pdf + print("\n[3] 개발자가이드.pdf") + src = os.path.join(DOCS_DIR, "WBX_Spring_Framework_개발자가이드.pdf") + out = os.path.join(DOCS_DIR, "WBX_Spring_Framework_개발자가이드.pdf") + replace_pages(src, { + 2: dev_page3, # Page 3: 사전 준비 (Docker/Redis 선택) + 3: dev_page4, # Page 4: Docker Compose (Redis 불필요) + 4: dev_page5, # Page 5: DevContainer (Redis 제외) + }, out) + + print("\n" + "=" * 50) + print("완료! 변경된 PDF:") + print(" - WBX_Spring_Framework_설치가이드_OnPremise.pdf (Page 3, 9)") + print(" - WBX_Spring_Framework_개발자가이드.pdf (Page 3, 4, 5)") + print(" - WBX_Spring_Framework_설치가이드_Cloud.pdf (변경 없음)") + + +if __name__ == "__main__": + main() diff --git a/wbx-spring-core/docs/개발환경_사전설치_가이드.txt b/wbx-spring-core/docs/개발환경_사전설치_가이드.txt index 8128186..158660f 100644 --- a/wbx-spring-core/docs/개발환경_사전설치_가이드.txt +++ b/wbx-spring-core/docs/개발환경_사전설치_가이드.txt @@ -81,9 +81,10 @@ 2. 선택 소프트웨어 (권장) -------------------------------------------------------------------------------- - [2-1] Docker Desktop + [2-1] Docker Desktop (선택 — DB 컨테이너 사용 시에만 필요) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 용도: 로컬 개발용 DB(MySQL/PostgreSQL) + Redis를 컨테이너로 실행 + 용도: 로컬 개발용 DB(MySQL/PostgreSQL)를 컨테이너로 실행 + ※ Redis는 Embedded Redis가 자동 구동되므로 Docker 불필요 * Windows winget install --id Docker.DockerDesktop @@ -119,19 +120,19 @@ GRANT ALL ON mos.* TO 'jsh'@'%'; - [2-3] Redis + [2-3] Redis (설치 불필요) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 용도: 캐시, 세션 저장소 - * Windows (Docker 권장, 네이티브 미지원) - docker run -d -p 6379:6379 redis:7-alpine + ※ WBX Spring Framework에 Embedded Redis가 내장되어 있어 별도 설치가 + 필요하지 않습니다. 앱 시작 시 다음 순서로 자동 동작합니다: - * macOS - brew install redis && brew services start redis + 1) 외부 Redis 감지 → 그대로 사용 (운영 환경) + 2) 외부 Redis 없음 → Embedded Redis 자동 시작 (개발 환경) + 3) Embedded Redis 실패 → 인메모리 캐시 전환 (최후 안전장치) - * Linux - sudo apt install -y redis-server (Ubuntu) - sudo yum install -y redis (RHEL) + 운영 환경에서 외부 Redis를 사용하려면 .env에 설정: + SPRING_DATA_REDIS_HOST=redis.company.com -------------------------------------------------------------------------------- @@ -151,7 +152,7 @@ scripts\install.bat (Windows) ./scripts/install.sh (Linux/macOS) - # 3) Docker로 MySQL + Redis 시작 + # 3) Docker로 MySQL 시작 (Redis는 Embedded Redis 자동 구동) docker compose -f docker-compose-dev.yml up -d # 4) .env 파일 수정 (DB 비밀번호를 docker-compose 설정에 맞춤) @@ -185,13 +186,11 @@ # 3) MySQL/PostgreSQL 설치 후 DB 생성 # 위 [2-2] 참고 + # (Redis는 Embedded Redis 자동 구동 — 설치 불필요) - # 4) Redis 설치 - # 위 [2-3] 참고 + # 4) .env 파일을 실제 DB 정보에 맞게 수정 - # 5) .env 파일을 실제 DB 정보에 맞게 수정 - - # 6~7) 앱 실행 및 확인 (위와 동일) + # 5~6) 앱 실행 및 확인 (위와 동일) -------------------------------------------------------------------------------- @@ -206,7 +205,7 @@ | MySQL 8.0 | 3306 | jsh | PW: jsh@ (기본 프로필) | | | | | root PW: rootpassword | | PostgreSQL 16 | 5432 | jsh | PW: jsh@ (--profile pg) | - | Redis 7 | 6379 | - | 인증 없음 (개발용) | + | Redis 7 | 6379 | - | Embedded Redis 자동 구동 | +------------------+--------+----------+------------------------------+ 프로필별 실행: @@ -250,7 +249,7 @@ | 8081 | wtm-api | WTM API, Admin, Swagger | | 3306 | MySQL | 기본 DB (mysql 프로필) | | 5432 | PostgreSQL | 대안 DB (postgresql 프로필) | - | 6379 | Redis | 캐시, 세션 | + | 6379 | Redis | Embedded Redis 자동 구동 (별도 설치 불필요)| | 5173 | wtm-frontend | Vue 3 개발 서버 | | 8001 | WBX FastAPI | 선택, 그룹웨어 동시 운영 시 | +--------+------------------+------------------------------------------+ @@ -273,9 +272,10 @@ 2) .env 파일의 DB_HOST, DB_PORT, DB_PASS 확인 3) telnet localhost 3306 으로 연결 가능 여부 확인 - Q: Redis 연결 실패 - A: docker ps 에서 redis 컨테이너 실행 중인지 확인 - 또는 Redis를 직접 설치하고 기본 포트(6379) 확인 + Q: Redis 관련 로그가 나옴 + A: Embedded Redis가 자동 구동됩니다. 별도 조치 불필요. + 로그에 "[WBX] Embedded Redis 시작" 출력 시 정상 동작. + 포트 6379가 이미 사용 중이면 외부 Redis를 자동 감지하여 사용합니다. Q: Lombok 관련 컴파일 에러 A: IDE에서 Annotation Processor 활성화 필요 diff --git a/wtm-frontend/src/core/auth/auth.guard.ts b/wtm-frontend/src/core/auth/auth.guard.ts index f7d8b6f..c69c469 100644 --- a/wtm-frontend/src/core/auth/auth.guard.ts +++ b/wtm-frontend/src/core/auth/auth.guard.ts @@ -2,10 +2,9 @@ import type { NavigationGuardWithThis } from 'vue-router'; import { authService } from './auth.service'; import { useAuthStore } from '@/modules/auth/auth.store'; -export const authGuard: NavigationGuardWithThis = async (_to, _from, next) => { +export const authGuard: NavigationGuardWithThis = async (_to, _from) => { if (!authService.isAuthenticated()) { - next({ name: 'login' }); - return; + return { name: 'login' }; } const authStore = useAuthStore(); @@ -13,5 +12,5 @@ export const authGuard: NavigationGuardWithThis = async (_to, _from, await authStore.fetchMe(); } - next(); + return true; };