From 28d3ba4836b70ae43361a6211aa7b317f05ea2e9 Mon Sep 17 00:00:00 2001 From: "DESKTOP-TKLFCPR\\ython" Date: Mon, 1 Jun 2026 19:43:09 +0900 Subject: [PATCH] refactor(cleanup): commit folder reorganization - scripts/, _archive/, docs/ restructure - Move backend/frontend/messenger/ old paths to _archive/ - Reorganize scripts into scripts/deploy, check, push, setup, misc - Move docs (pptx, docx) to docs/ - Add .claude agents and skills for fullstack/folder-cleanup harness - workspace/ projects remain intact Co-Authored-By: Claude Sonnet 4.6 --- .claude/agents/cross-system-qa.md | 63 ++++ .claude/agents/folder-organizer.md | 66 ++++ .claude/agents/full-stack-analyst.md | 51 +++ .claude/agents/homepage-dev.md | 70 ++++ .claude/agents/itsm-dev.md | 62 ++++ .claude/agents/manager-dev.md | 61 ++++ .claude/agents/messenger-dev.md | 71 ++++ .../folder-cleanup-orchestrator/SKILL.md | 90 +++++ .../guardia-fullstack-orchestrator/SKILL.md | 132 +++++++ .../references/system-landscape.md | 161 ++++++++ CLAUDE.md | 45 +++ Jenkinsfile => _archive/Jenkinsfile | 0 .../.mvn/wrapper/maven-wrapper.properties | 0 {backend => _archive/backend}/pom.xml | 0 .../co/zioinfo/web/ZioinfoWebApplication.java | 0 .../zioinfo/web/config/DataInitializer.java | 0 .../co/zioinfo/web/config/SecurityConfig.java | 0 .../web/controller/AdminController.java | 0 .../zioinfo/web/controller/ApiController.java | 0 .../kr/co/zioinfo/web/model/AdminUser.java | 0 .../java/kr/co/zioinfo/web/model/Inquiry.java | 0 .../java/kr/co/zioinfo/web/model/News.java | 0 .../java/kr/co/zioinfo/web/model/Recruit.java | 0 .../web/repository/AdminUserRepository.java | 0 .../web/repository/InquiryRepository.java | 0 .../web/repository/NewsRepository.java | 0 .../web/repository/RecruitRepository.java | 0 .../zioinfo/web/security/JwtAuthFilter.java | 0 .../kr/co/zioinfo/web/security/JwtUtil.java | 0 .../zioinfo/web/service/InquiryService.java | 0 .../co/zioinfo/web/service/NewsService.java | 0 .../src/main/resources/application.yml | 0 .../static/assets/AdminDashboard-B5ryl_KI.js | 0 .../static/assets/AdminInquiry-BBFBdE8S.js | 0 .../static/assets/AdminLayout-uWX9KsdF.js | 0 .../static/assets/AdminLogin-DcRT5LbX.js | 0 .../static/assets/AdminNews-CDSgPR9E.js | 0 .../static/assets/AdminRecruit-CfX4mhQb.js | 0 .../static/assets/AdminSettings-DaHEGHsg.js | 0 .../static/assets/Business-EGnXphuY.js | 0 .../static/assets/Business-EM7OeA4c.css | 0 .../static/assets/Common-BmvLh5lB.css | 0 .../static/assets/Company-BOdWAIQ4.js | 0 .../static/assets/Company-qD6qaVvP.css | 0 .../static/assets/Contact-C2ZwoM3_.css | 0 .../static/assets/Contact-C6p_tBWi.js | 0 .../static/assets/GuardiaDetail-5Pm8bk4O.js | 0 .../static/assets/GuardiaDetail-Ax0ubrjA.css | 0 .../resources/static/assets/Home-BC38QtTl.js | 0 .../resources/static/assets/Home-jagO1aR4.css | 0 .../static/assets/NewsPage-BgXQ2CUT.css | 0 .../static/assets/NewsPage-mgytOZhS.js | 0 .../static/assets/NotFound-KZZDVQMb.js | 0 .../static/assets/Recruit-CbW65yqF.css | 0 .../static/assets/Recruit-DlKGM6KQ.js | 0 .../static/assets/SolutionPage-C7_Wcm8g.css | 0 .../static/assets/SolutionPage-Da0Vpoc-.js | 0 .../static/assets/Support-C5QVP1gW.js | 0 .../static/assets/Support-DvGESosS.css | 0 .../static/assets/admin-BHL-7hu0.css | 0 .../resources/static/assets/index-ChpGil2q.js | 0 .../resources/static/assets/index-DcNlVx-A.js | 0 .../static/assets/index-Dk81znn6.css | 0 .../src/main/resources/static/favicon.ico | Bin .../src/main/resources/static/index.html | 0 .../src/main/resources/static/logo-white.png | Bin .../src/main/resources/static/logo.png | Bin .../static/screenshots/01_dashboard.png | Bin .../resources/static/screenshots/01_home.png | Bin .../static/screenshots/01_home_viewport.png | Bin .../static/screenshots/02_guardia.png | Bin .../screenshots/02_guardia_viewport.png | Bin .../static/screenshots/02_sr_list.png | Bin .../static/screenshots/03_company.png | Bin .../screenshots/03_company_viewport.png | Bin .../static/screenshots/03_si_project.png | Bin .../static/screenshots/04_contact.png | Bin .../screenshots/04_contact_viewport.png | Bin .../static/screenshots/04_incidents.png | Bin .../static/screenshots/05_agents.png | Bin .../resources/static/screenshots/05_news.png | Bin .../static/screenshots/05_news_viewport.png | Bin .../static/screenshots/06_license.png | Bin .../static/screenshots/06_mobile_home.png | Bin .../static/screenshots/all-pages-result.json | 0 .../static/screenshots/business_partner.png | Bin .../static/screenshots/business_ref.png | Bin .../static/screenshots/company_ci.png | Bin .../static/screenshots/company_greeting.png | Bin .../static/screenshots/company_history.png | Bin .../static/screenshots/company_location.png | Bin .../static/screenshots/company_org.png | Bin .../resources/static/screenshots/guardia.png | Bin .../resources/static/screenshots/home.png | Bin .../static/screenshots/news_blog.png | Bin .../static/screenshots/news_newsroom.png | Bin .../static/screenshots/recruit_apply.png | Bin .../static/screenshots/recruit_jobs.png | Bin .../static/screenshots/recruit_welfare.png | Bin .../static/screenshots/solution_bi.png | Bin .../static/screenshots/solution_crm.png | Bin .../static/screenshots/solution_erp.png | Bin .../static/screenshots/support_catalog.png | Bin .../static/screenshots/support_contact.png | Bin .../static/screenshots/support_faq.png | Bin .../static/screenshots/support_notice.png | Bin .../static/screenshots/test-result.json | 0 {frontend => _archive/frontend}/index.html | 0 .../frontend}/package-lock.json | 0 {frontend => _archive/frontend}/package.json | 0 .../frontend}/public/favicon.ico | Bin .../frontend}/public/index.html | 0 .../frontend}/public/logo-white.png | Bin .../frontend}/public/logo.png | Bin .../public/screenshots/01_dashboard.png | Bin .../frontend}/public/screenshots/01_home.png | Bin .../public/screenshots/01_home_viewport.png | Bin .../public/screenshots/02_guardia.png | Bin .../screenshots/02_guardia_viewport.png | Bin .../public/screenshots/02_sr_list.png | Bin .../public/screenshots/03_company.png | Bin .../screenshots/03_company_viewport.png | Bin .../public/screenshots/03_si_project.png | Bin .../public/screenshots/04_contact.png | Bin .../screenshots/04_contact_viewport.png | Bin .../public/screenshots/04_incidents.png | Bin .../public/screenshots/05_agents.png | Bin .../frontend}/public/screenshots/05_news.png | Bin .../public/screenshots/05_news_viewport.png | Bin .../public/screenshots/06_license.png | Bin .../public/screenshots/06_mobile_home.png | Bin .../public/screenshots/all-pages-result.json | 0 .../public/screenshots/business_partner.png | Bin .../public/screenshots/business_ref.png | Bin .../public/screenshots/company_ci.png | Bin .../public/screenshots/company_greeting.png | Bin .../public/screenshots/company_history.png | Bin .../public/screenshots/company_location.png | Bin .../public/screenshots/company_org.png | Bin .../frontend}/public/screenshots/guardia.png | Bin .../frontend}/public/screenshots/home.png | Bin .../public/screenshots/news_blog.png | Bin .../public/screenshots/news_newsroom.png | Bin .../public/screenshots/recruit_apply.png | Bin .../public/screenshots/recruit_jobs.png | Bin .../public/screenshots/recruit_welfare.png | Bin .../public/screenshots/solution_bi.png | Bin .../public/screenshots/solution_crm.png | Bin .../public/screenshots/solution_erp.png | Bin .../public/screenshots/support_catalog.png | Bin .../public/screenshots/support_contact.png | Bin .../public/screenshots/support_faq.png | Bin .../public/screenshots/support_notice.png | Bin .../public/screenshots/test-result.json | 0 {frontend => _archive/frontend}/src/App.jsx | 0 .../src/components/layout/Footer.css | 0 .../src/components/layout/Footer.jsx | 0 .../src/components/layout/Header.css | 0 .../src/components/layout/Header.jsx | 0 {frontend => _archive/frontend}/src/main.jsx | 0 .../frontend}/src/pages/Business.css | 0 .../frontend}/src/pages/Business.jsx | 0 .../frontend}/src/pages/Common.css | 2 +- .../frontend}/src/pages/Company.css | 0 .../frontend}/src/pages/Company.jsx | 0 .../frontend}/src/pages/Contact.css | 0 .../frontend}/src/pages/Contact.jsx | 0 .../frontend}/src/pages/GuardiaDetail.css | 0 .../frontend}/src/pages/GuardiaDetail.jsx | 0 .../frontend}/src/pages/Home.css | 0 .../frontend}/src/pages/Home.jsx | 0 .../frontend}/src/pages/NewsPage.css | 0 .../frontend}/src/pages/NewsPage.jsx | 0 .../frontend}/src/pages/NotFound.jsx | 2 +- .../frontend}/src/pages/Recruit.css | 0 .../frontend}/src/pages/Recruit.jsx | 0 .../frontend}/src/pages/SolutionPage.css | 0 .../frontend}/src/pages/SolutionPage.jsx | 0 .../frontend}/src/pages/Support.css | 0 .../frontend}/src/pages/Support.jsx | 0 .../src/pages/admin/AdminDashboard.jsx | 0 .../src/pages/admin/AdminInquiry.jsx | 0 .../frontend}/src/pages/admin/AdminLayout.jsx | 0 .../frontend}/src/pages/admin/AdminLogin.jsx | 0 .../frontend}/src/pages/admin/AdminNews.jsx | 0 .../src/pages/admin/AdminRecruit.jsx | 0 .../src/pages/admin/AdminSettings.jsx | 0 .../frontend}/src/pages/admin/admin.css | 0 .../frontend}/src/styles/global.css | 0 .../frontend}/vite.config.js | 0 .../messenger}/core/__init__.py | 0 {messenger => _archive/messenger}/core/bot.py | 0 .../messenger}/core/chatbot.py | 0 {messenger => _archive/messenger}/main.py | 0 .../messenger}/models/__init__.py | 0 .../messenger}/models/message.py | 0 .../messenger}/requirements.txt | 0 .../messenger}/routers/__init__.py | 0 .../messenger}/routers/messages.py | 0 .../messenger}/routers/webhook.py | 0 .../messenger}/routers/ws_relay.py | 0 .../messenger}/static/app.js | 0 .../messenger}/static/index.html | 0 .../messenger}/static/style.css | 0 .../package-lock.json | 0 package.json => _archive/package.json | 0 .../AI 오케스트레이터와 인간 엔지니어 간의 협업.docx | Bin .../CICD-구축건_20260309.pptx | Bin 메신져.docx => docs/메신져.docx | Bin 특허출원.docx => docs/특허출원.docx | Bin scripts/README.md | 11 + .../misc/find_manager_login.py | 0 .../misc/fix_gitea_push.py | 0 .../misc/fix_logo_manager.py | 0 .../misc/make_dark_logo.py | 0 .../misc/pgvector_grant.py | 0 .../misc/pgvector_test.py | 0 .../misc/playwright_home.py | 0 .../misc/playwright_remaining.py | 0 .../misc/playwright_screenshots.py | 0 scripts/misc/run_tests.py | 99 +++++ .../misc/test-all-pages.js | 0 .../misc/test-homepage.js | 0 push_final2.py => scripts/push/push_final2.py | 0 .../push/push_gitea_final.py | 0 .../push/push_gitea_internal.py | 0 .../push/push_remaining.py | 0 push_v3.py => scripts/push/push_v3.py | 0 .../push/push_via_server.py | 0 scripts/setup/cicd_full_setup.py | 344 ++++++++++++++++++ .../setup/cicd_status.py | 0 scripts/setup/jenkins_check_users.py | 31 ++ scripts/setup/jenkins_configure.py | 100 +++++ scripts/setup/jenkins_fix.py | 21 ++ scripts/setup/jenkins_reset.py | 58 +++ scripts/setup/jenkins_set_password.py | 62 ++++ scripts/setup/jenkins_setup2.py | 63 ++++ .../setup/setup_gitea2.py | 0 .../setup/setup_gitea_repos.py | 0 scripts/setup/setup_jenkins.py | 95 +++++ .../setup/setup_webhooks.py | 0 guardia_setup.ps1 => setup/guardia_setup.ps1 | 0 workspace/guardia-messenger/Jenkinsfile | 46 +++ .../frontend/src/components/layout/Header.css | 4 +- .../frontend/src/components/layout/Header.jsx | 8 +- .../frontend/src/pages/SolutionPage.jsx | 1 + 246 files changed, 1812 insertions(+), 7 deletions(-) create mode 100644 .claude/agents/cross-system-qa.md create mode 100644 .claude/agents/folder-organizer.md create mode 100644 .claude/agents/full-stack-analyst.md create mode 100644 .claude/agents/homepage-dev.md create mode 100644 .claude/agents/itsm-dev.md create mode 100644 .claude/agents/manager-dev.md create mode 100644 .claude/agents/messenger-dev.md create mode 100644 .claude/skills/folder-cleanup-orchestrator/SKILL.md create mode 100644 .claude/skills/guardia-fullstack-orchestrator/SKILL.md create mode 100644 .claude/skills/guardia-fullstack-orchestrator/references/system-landscape.md rename Jenkinsfile => _archive/Jenkinsfile (100%) rename {backend => _archive/backend}/.mvn/wrapper/maven-wrapper.properties (100%) rename {backend => _archive/backend}/pom.xml (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/ZioinfoWebApplication.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/config/DataInitializer.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/config/SecurityConfig.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/controller/AdminController.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/controller/ApiController.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/model/AdminUser.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/model/Inquiry.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/model/News.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/model/Recruit.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/repository/AdminUserRepository.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/repository/InquiryRepository.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/repository/NewsRepository.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/repository/RecruitRepository.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/security/JwtAuthFilter.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/security/JwtUtil.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/service/InquiryService.java (100%) rename {backend => _archive/backend}/src/main/java/kr/co/zioinfo/web/service/NewsService.java (100%) rename {backend => _archive/backend}/src/main/resources/application.yml (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/AdminDashboard-B5ryl_KI.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/AdminInquiry-BBFBdE8S.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/AdminLayout-uWX9KsdF.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/AdminLogin-DcRT5LbX.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/AdminNews-CDSgPR9E.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/AdminRecruit-CfX4mhQb.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/AdminSettings-DaHEGHsg.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Business-EGnXphuY.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Business-EM7OeA4c.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Common-BmvLh5lB.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Company-BOdWAIQ4.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Company-qD6qaVvP.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Contact-C2ZwoM3_.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Contact-C6p_tBWi.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/GuardiaDetail-5Pm8bk4O.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/GuardiaDetail-Ax0ubrjA.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Home-BC38QtTl.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Home-jagO1aR4.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/NewsPage-BgXQ2CUT.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/NewsPage-mgytOZhS.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/NotFound-KZZDVQMb.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Recruit-CbW65yqF.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Recruit-DlKGM6KQ.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/SolutionPage-C7_Wcm8g.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/SolutionPage-Da0Vpoc-.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Support-C5QVP1gW.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/Support-DvGESosS.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/admin-BHL-7hu0.css (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/index-ChpGil2q.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/index-DcNlVx-A.js (100%) rename {backend => _archive/backend}/src/main/resources/static/assets/index-Dk81znn6.css (100%) rename {backend => _archive/backend}/src/main/resources/static/favicon.ico (100%) rename {backend => _archive/backend}/src/main/resources/static/index.html (100%) rename {backend => _archive/backend}/src/main/resources/static/logo-white.png (100%) rename {backend => _archive/backend}/src/main/resources/static/logo.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/01_dashboard.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/01_home.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/01_home_viewport.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/02_guardia.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/02_guardia_viewport.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/02_sr_list.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/03_company.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/03_company_viewport.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/03_si_project.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/04_contact.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/04_contact_viewport.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/04_incidents.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/05_agents.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/05_news.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/05_news_viewport.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/06_license.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/06_mobile_home.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/all-pages-result.json (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/business_partner.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/business_ref.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/company_ci.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/company_greeting.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/company_history.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/company_location.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/company_org.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/guardia.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/home.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/news_blog.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/news_newsroom.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/recruit_apply.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/recruit_jobs.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/recruit_welfare.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/solution_bi.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/solution_crm.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/solution_erp.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/support_catalog.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/support_contact.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/support_faq.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/support_notice.png (100%) rename {backend => _archive/backend}/src/main/resources/static/screenshots/test-result.json (100%) rename {frontend => _archive/frontend}/index.html (100%) rename {frontend => _archive/frontend}/package-lock.json (100%) rename {frontend => _archive/frontend}/package.json (100%) rename {frontend => _archive/frontend}/public/favicon.ico (100%) rename {frontend => _archive/frontend}/public/index.html (100%) rename {frontend => _archive/frontend}/public/logo-white.png (100%) rename {frontend => _archive/frontend}/public/logo.png (100%) rename {frontend => _archive/frontend}/public/screenshots/01_dashboard.png (100%) rename {frontend => _archive/frontend}/public/screenshots/01_home.png (100%) rename {frontend => _archive/frontend}/public/screenshots/01_home_viewport.png (100%) rename {frontend => _archive/frontend}/public/screenshots/02_guardia.png (100%) rename {frontend => _archive/frontend}/public/screenshots/02_guardia_viewport.png (100%) rename {frontend => _archive/frontend}/public/screenshots/02_sr_list.png (100%) rename {frontend => _archive/frontend}/public/screenshots/03_company.png (100%) rename {frontend => _archive/frontend}/public/screenshots/03_company_viewport.png (100%) rename {frontend => _archive/frontend}/public/screenshots/03_si_project.png (100%) rename {frontend => _archive/frontend}/public/screenshots/04_contact.png (100%) rename {frontend => _archive/frontend}/public/screenshots/04_contact_viewport.png (100%) rename {frontend => _archive/frontend}/public/screenshots/04_incidents.png (100%) rename {frontend => _archive/frontend}/public/screenshots/05_agents.png (100%) rename {frontend => _archive/frontend}/public/screenshots/05_news.png (100%) rename {frontend => _archive/frontend}/public/screenshots/05_news_viewport.png (100%) rename {frontend => _archive/frontend}/public/screenshots/06_license.png (100%) rename {frontend => _archive/frontend}/public/screenshots/06_mobile_home.png (100%) rename {frontend => _archive/frontend}/public/screenshots/all-pages-result.json (100%) rename {frontend => _archive/frontend}/public/screenshots/business_partner.png (100%) rename {frontend => _archive/frontend}/public/screenshots/business_ref.png (100%) rename {frontend => _archive/frontend}/public/screenshots/company_ci.png (100%) rename {frontend => _archive/frontend}/public/screenshots/company_greeting.png (100%) rename {frontend => _archive/frontend}/public/screenshots/company_history.png (100%) rename {frontend => _archive/frontend}/public/screenshots/company_location.png (100%) rename {frontend => _archive/frontend}/public/screenshots/company_org.png (100%) rename {frontend => _archive/frontend}/public/screenshots/guardia.png (100%) rename {frontend => _archive/frontend}/public/screenshots/home.png (100%) rename {frontend => _archive/frontend}/public/screenshots/news_blog.png (100%) rename {frontend => _archive/frontend}/public/screenshots/news_newsroom.png (100%) rename {frontend => _archive/frontend}/public/screenshots/recruit_apply.png (100%) rename {frontend => _archive/frontend}/public/screenshots/recruit_jobs.png (100%) rename {frontend => _archive/frontend}/public/screenshots/recruit_welfare.png (100%) rename {frontend => _archive/frontend}/public/screenshots/solution_bi.png (100%) rename {frontend => _archive/frontend}/public/screenshots/solution_crm.png (100%) rename {frontend => _archive/frontend}/public/screenshots/solution_erp.png (100%) rename {frontend => _archive/frontend}/public/screenshots/support_catalog.png (100%) rename {frontend => _archive/frontend}/public/screenshots/support_contact.png (100%) rename {frontend => _archive/frontend}/public/screenshots/support_faq.png (100%) rename {frontend => _archive/frontend}/public/screenshots/support_notice.png (100%) rename {frontend => _archive/frontend}/public/screenshots/test-result.json (100%) rename {frontend => _archive/frontend}/src/App.jsx (100%) rename {frontend => _archive/frontend}/src/components/layout/Footer.css (100%) rename {frontend => _archive/frontend}/src/components/layout/Footer.jsx (100%) rename {frontend => _archive/frontend}/src/components/layout/Header.css (100%) rename {frontend => _archive/frontend}/src/components/layout/Header.jsx (100%) rename {frontend => _archive/frontend}/src/main.jsx (100%) rename {frontend => _archive/frontend}/src/pages/Business.css (100%) rename {frontend => _archive/frontend}/src/pages/Business.jsx (100%) rename {frontend => _archive/frontend}/src/pages/Common.css (99%) rename {frontend => _archive/frontend}/src/pages/Company.css (100%) rename {frontend => _archive/frontend}/src/pages/Company.jsx (100%) rename {frontend => _archive/frontend}/src/pages/Contact.css (100%) rename {frontend => _archive/frontend}/src/pages/Contact.jsx (100%) rename {frontend => _archive/frontend}/src/pages/GuardiaDetail.css (100%) rename {frontend => _archive/frontend}/src/pages/GuardiaDetail.jsx (100%) rename {frontend => _archive/frontend}/src/pages/Home.css (100%) rename {frontend => _archive/frontend}/src/pages/Home.jsx (100%) rename {frontend => _archive/frontend}/src/pages/NewsPage.css (100%) rename {frontend => _archive/frontend}/src/pages/NewsPage.jsx (100%) rename {frontend => _archive/frontend}/src/pages/NotFound.jsx (99%) rename {frontend => _archive/frontend}/src/pages/Recruit.css (100%) rename {frontend => _archive/frontend}/src/pages/Recruit.jsx (100%) rename {frontend => _archive/frontend}/src/pages/SolutionPage.css (100%) rename {frontend => _archive/frontend}/src/pages/SolutionPage.jsx (100%) rename {frontend => _archive/frontend}/src/pages/Support.css (100%) rename {frontend => _archive/frontend}/src/pages/Support.jsx (100%) rename {frontend => _archive/frontend}/src/pages/admin/AdminDashboard.jsx (100%) rename {frontend => _archive/frontend}/src/pages/admin/AdminInquiry.jsx (100%) rename {frontend => _archive/frontend}/src/pages/admin/AdminLayout.jsx (100%) rename {frontend => _archive/frontend}/src/pages/admin/AdminLogin.jsx (100%) rename {frontend => _archive/frontend}/src/pages/admin/AdminNews.jsx (100%) rename {frontend => _archive/frontend}/src/pages/admin/AdminRecruit.jsx (100%) rename {frontend => _archive/frontend}/src/pages/admin/AdminSettings.jsx (100%) rename {frontend => _archive/frontend}/src/pages/admin/admin.css (100%) rename {frontend => _archive/frontend}/src/styles/global.css (100%) rename {frontend => _archive/frontend}/vite.config.js (100%) rename {messenger => _archive/messenger}/core/__init__.py (100%) rename {messenger => _archive/messenger}/core/bot.py (100%) rename {messenger => _archive/messenger}/core/chatbot.py (100%) rename {messenger => _archive/messenger}/main.py (100%) rename {messenger => _archive/messenger}/models/__init__.py (100%) rename {messenger => _archive/messenger}/models/message.py (100%) rename {messenger => _archive/messenger}/requirements.txt (100%) rename {messenger => _archive/messenger}/routers/__init__.py (100%) rename {messenger => _archive/messenger}/routers/messages.py (100%) rename {messenger => _archive/messenger}/routers/webhook.py (100%) rename {messenger => _archive/messenger}/routers/ws_relay.py (100%) rename {messenger => _archive/messenger}/static/app.js (100%) rename {messenger => _archive/messenger}/static/index.html (100%) rename {messenger => _archive/messenger}/static/style.css (100%) rename package-lock.json => _archive/package-lock.json (100%) rename package.json => _archive/package.json (100%) rename AI 오케스트레이터와 인간 엔지니어 간의 협업.docx => docs/AI 오케스트레이터와 인간 엔지니어 간의 협업.docx (100%) rename CICD-구축건_20260309.pptx => docs/CICD-구축건_20260309.pptx (100%) rename 메신져.docx => docs/메신져.docx (100%) rename 특허출원.docx => docs/특허출원.docx (100%) create mode 100644 scripts/README.md rename find_manager_login.py => scripts/misc/find_manager_login.py (100%) rename fix_gitea_push.py => scripts/misc/fix_gitea_push.py (100%) rename fix_logo_manager.py => scripts/misc/fix_logo_manager.py (100%) rename make_dark_logo.py => scripts/misc/make_dark_logo.py (100%) rename pgvector_grant.py => scripts/misc/pgvector_grant.py (100%) rename pgvector_test.py => scripts/misc/pgvector_test.py (100%) rename playwright_home.py => scripts/misc/playwright_home.py (100%) rename playwright_remaining.py => scripts/misc/playwright_remaining.py (100%) rename playwright_screenshots.py => scripts/misc/playwright_screenshots.py (100%) create mode 100644 scripts/misc/run_tests.py rename test-all-pages.js => scripts/misc/test-all-pages.js (100%) rename test-homepage.js => scripts/misc/test-homepage.js (100%) rename push_final2.py => scripts/push/push_final2.py (100%) rename push_gitea_final.py => scripts/push/push_gitea_final.py (100%) rename push_gitea_internal.py => scripts/push/push_gitea_internal.py (100%) rename push_remaining.py => scripts/push/push_remaining.py (100%) rename push_v3.py => scripts/push/push_v3.py (100%) rename push_via_server.py => scripts/push/push_via_server.py (100%) create mode 100644 scripts/setup/cicd_full_setup.py rename cicd_status.py => scripts/setup/cicd_status.py (100%) create mode 100644 scripts/setup/jenkins_check_users.py create mode 100644 scripts/setup/jenkins_configure.py create mode 100644 scripts/setup/jenkins_fix.py create mode 100644 scripts/setup/jenkins_reset.py create mode 100644 scripts/setup/jenkins_set_password.py create mode 100644 scripts/setup/jenkins_setup2.py rename setup_gitea2.py => scripts/setup/setup_gitea2.py (100%) rename setup_gitea_repos.py => scripts/setup/setup_gitea_repos.py (100%) create mode 100644 scripts/setup/setup_jenkins.py rename setup_webhooks.py => scripts/setup/setup_webhooks.py (100%) rename guardia_setup.ps1 => setup/guardia_setup.ps1 (100%) create mode 100644 workspace/guardia-messenger/Jenkinsfile diff --git a/.claude/agents/cross-system-qa.md b/.claude/agents/cross-system-qa.md new file mode 100644 index 00000000..79cdbe31 --- /dev/null +++ b/.claude/agents/cross-system-qa.md @@ -0,0 +1,63 @@ +--- +name: cross-system-qa +description: "GUARDiA 크로스 시스템 통합 QA 에이전트. ITSM API 계약과 Manager·Messenger·홈페이지의 클라이언트 호출을 대조하여 경계면 불일치를 검출한다. API 응답 shape, 인증 흐름, 보안 필드 노출 여부를 검증한다." +model: opus +--- + +# Cross-System QA — 통합 QA 에이전트 + +## 핵심 역할 + +4개 시스템의 경계면(API 계약, 인증 흐름, 데이터 shape)을 교차 검증한다. + +## 검증 범위 + +### 1. API 계약 검증 + +ITSM 라우터 엔드포인트 vs Manager/Messenger 호출 URL 대조: + +```python +# 검사 대상 — ITSM 라우터에서 추출 +grep -r "router.get\|router.post\|router.put\|router.delete" workspace/guardia-itsm/routers/ + +# 대조 대상 — Manager API 클라이언트 +grep -r "axios\.\|fetch(" workspace/guardia-manager/frontend/src/ + +# 대조 대상 — Messenger +grep -r "axios\.\|fetch(" workspace/guardia-messenger/app/ +``` + +### 2. 보안 필드 노출 검증 + +```python +# ITSM API 응답에서 민감 필드 노출 여부 확인 +grep -r "ip_addr\|ssh_user\|os_pw_enc" workspace/guardia-itsm/routers/ +# → 이 필드들이 Response 모델에 포함되면 보안 위반 +``` + +### 3. 인증 흐름 검증 + +- ITSM `/api/auth/login` → JWT 발급 +- Manager `core/auth.py` → 동일 JWT 검증 방식 확인 +- Messenger `login.tsx` → `SecureStore`에 토큰 저장 확인 + +### 4. 데이터 타입 일관성 검증 + +ITSM Pydantic 스키마(models.py)의 필드 타입 vs Messenger TypeScript 인터페이스 대조: +- `SROut.id: int` ↔ Messenger `sr.id: number` +- `SROut.status: str` ↔ Messenger `sr.status: string` +- `SROut.created_at: datetime` ↔ Messenger `sr.created_at: string` + +## 검증 실행 절차 + +1. **변경 범위 파악**: full-stack-analyst로부터 변경된 파일 목록 수신 +2. **영향 경계면 식별**: 변경된 API 엔드포인트를 호출하는 다른 시스템 파일 찾기 +3. **Shape 비교**: 요청/응답 모델 필드 타입·이름 일치 확인 +4. **보안 스캔**: 민감 필드 노출, 스택트레이스 노출 패턴 확인 +5. **검증 보고서 작성**: `_workspace/qa_report_{timestamp}.md` + +## 팀 통신 프로토콜 + +- **수신**: guardia-fullstack-orchestrator로부터 QA 요청 (변경 완료 후) +- **발신**: guardia-fullstack-orchestrator에게 QA 결과 보고 +- **이슈 발견 시**: 해당 시스템 dev 에이전트(itsm-dev, manager-dev 등)에게 수정 요청 diff --git a/.claude/agents/folder-organizer.md b/.claude/agents/folder-organizer.md new file mode 100644 index 00000000..c8b38d0b --- /dev/null +++ b/.claude/agents/folder-organizer.md @@ -0,0 +1,66 @@ +--- +name: folder-organizer +description: "GUARDiA 루트 폴더 정리 에이전트. 루트에 산재한 Python 스크립트·임시 파일·구버전 소스를 용도별로 분류·이동·아카이브한다." +model: opus +--- + +# Folder Organizer — 폴더 정리 에이전트 + +## 핵심 역할 + +`C:\GUARDiA\` 루트의 임시 파일·스크립트·구버전 소스를 정해진 구조로 이동한다. + +## 목표 구조 + +``` +C:\GUARDiA\ +├── workspace/ # 4개 프로젝트 소스 (불변) +├── repos/ # Gitea push용 (불변) +├── .claude/ # 하네스 (불변) +├── docs/ # 설계 문서 + 문서 파일 통합 +├── scripts/ # 루트 임시 스크립트 → 분류 +│ ├── deploy/ # deploy_*.py +│ ├── check/ # check_*.py +│ ├── push/ # push_*.py +│ ├── setup/ # setup_*.py, jenkins_*.py, install_*.py +│ └── misc/ # 기타 .py .js +├── deploy/ # 서버 배포 sh/ps1 (유지) +├── setup/ # 설치 스크립트 (유지) +├── _archive/ # 구버전 소스 (backend/, frontend/, messenger/) +├── certification/ # GS인증 서류 (유지) +├── logo/ # 로고 (유지) +├── screenshot/ # 스크린샷 (유지) +├── design-overhaul/ # 디자인 작업 (유지) +├── testcase/ # 테스트케이스 (유지) +├── projects/ # 고객 프로젝트 (유지) +├── ollama/ # Ollama 설정 (유지) +├── docker/ # Docker 설정 (유지) +└── CLAUDE.md # 진입점 (불변) +``` + +## 이동 규칙 + +| 패턴 | 이동 대상 | +|------|---------| +| `deploy_*.py` | `scripts/deploy/` | +| `check_*.py` | `scripts/check/` | +| `push_*.py` | `scripts/push/` | +| `setup_*.py`, `jenkins_*.py`, `install_*.py`, `cicd_*.py` | `scripts/setup/` | +| 나머지 루트 `.py` | `scripts/misc/` | +| 루트 `.js` 파일 | `scripts/misc/` | +| `*.docx`, `*.pptx` | `docs/` | +| `*.log` | 삭제 | +| `backend/`, `frontend/`, `messenger/`, `agents/` | `_archive/` | +| 루트 `Jenkinsfile` | `_archive/` | +| 루트 `package.json`, `package-lock.json` | `_archive/` | +| `app_screens.html` | `_archive/` | + +## 절대 이동하지 않는 것 + +- `CLAUDE.md`, `.claude/`, `.git/`, `.gitignore`, `.gitea/` +- `workspace/`, `repos/`, `docs/`, `deploy/`, `setup/` +- `certification/`, `logo/`, `screenshot/`, `design-overhaul/` +- `testcase/`, `projects/`, `ollama/`, `docker/` +- `docker-compose*.yml`, `Dockerfile` +- `zio-server-key.pem` +- `skills/`, `plugins/`, `paperclip/`, `template/`, `scripts/` diff --git a/.claude/agents/full-stack-analyst.md b/.claude/agents/full-stack-analyst.md new file mode 100644 index 00000000..f601e44a --- /dev/null +++ b/.claude/agents/full-stack-analyst.md @@ -0,0 +1,51 @@ +--- +name: full-stack-analyst +description: "GUARDiA 전체 시스템(ITSM·홈페이지·Manager·Messenger) 코드베이스 분석 에이전트. 4개 시스템의 API 계약, 공유 데이터 모델, 의존 관계, 기술 부채를 파악하고 크로스 시스템 변경 영향 분석을 수행한다." +model: opus +--- + +# Full-Stack Analyst — 크로스 시스템 분석 에이전트 + +## 핵심 역할 + +4개 GUARDiA 시스템 전체를 스캔하여 시스템 간 의존 관계·API 계약·데이터 흐름을 분석한다. + +## 담당 시스템 맵 + +| 시스템 | 경로 | 언어/프레임워크 | 포트 | +|--------|------|---------------|------| +| GUARDiA ITSM | `workspace/guardia-itsm/` | Python 3.11 + FastAPI | 9001 | +| zioinfo-web | `workspace/zioinfo-web/` | Java 17 + Spring Boot 3.2.5 | 8082 | +| GUARDiA Manager | `workspace/guardia-manager/` | Python FastAPI + React TS | 8002/8090 | +| GUARDiA Messenger | `workspace/guardia-messenger/` | React Native + Expo 51 | EAS | + +## 시스템 간 의존 관계 + +``` +zioinfo-web (홈페이지, 독립) + ↓ inquiry form → ITSM API +GUARDiA ITSM (중앙 허브, localhost:9001) + ↑ REST /api/* ↑ WebSocket ws:// +GUARDiA Manager (관제, :8002) GUARDiA Messenger (모바일, EAS) +``` + +## 분석 작업 원칙 + +1. **API 계약 추출**: ITSM routers/*.py에서 엔드포인트 목록 추출 → Manager·Messenger가 호출하는 URL 대조 +2. **모델 일관성 검증**: ITSM models.py의 Pydantic 스키마와 Messenger의 TypeScript 타입 비교 +3. **인증 흐름 추적**: JWT 발급(ITSM /api/auth/login) → Manager·Messenger 사용 패턴 확인 +4. **보안 위반 스캔**: `ip_addr`, `ssh_user`, `os_pw_enc` 필드가 API 응답에 노출되는지 검사 + +## 크로스 시스템 변경 영향 분석 + +변경 요청 수신 시: +1. 변경 대상 파일/엔드포인트 파악 +2. 해당 API를 호출하는 다른 시스템 탐색 (Grep 활용) +3. 영향 받는 TypeScript 타입·컴포넌트 목록 제시 +4. 변경 순서 권장 (DB 모델 → ITSM router → Manager API client → Messenger hook 순) + +## 팀 통신 프로토콜 + +- **수신**: guardia-fullstack-orchestrator로부터 분석 요청 +- **발신**: itsm-dev, homepage-dev, manager-dev, messenger-dev에게 구체적 변경 지침 전달 +- **산출물**: `_workspace/analysis_{timestamp}.md`에 영향 분석 보고서 저장 diff --git a/.claude/agents/homepage-dev.md b/.claude/agents/homepage-dev.md new file mode 100644 index 00000000..bf636e53 --- /dev/null +++ b/.claude/agents/homepage-dev.md @@ -0,0 +1,70 @@ +--- +name: homepage-dev +description: "지오정보기술 홈페이지(zioinfo-web) 개발 에이전트. workspace/zioinfo-web/ 경로에서 Spring Boot 3.2.5 백엔드·React 18/Vite 프론트엔드 개발을 담당한다. CMS 콘텐츠 DB화, 관리자 CRUD, SEO 최적화를 수행한다." +model: opus +--- + +# Homepage Dev — zioinfo-web 개발 에이전트 + +## 핵심 역할 + +`workspace/zioinfo-web/` 코드베이스에서 백엔드 API·프론트엔드 컴포넌트 개발을 수행한다. + +## 코드베이스 핵심 구조 + +``` +workspace/zioinfo-web/ +├── backend/ # Spring Boot 3.2.5 +│ ├── pom.xml # Java 17, Spring Security, JPA, Mail +│ ├── src/main/java/kr/co/zioinfo/ +│ │ ├── entity/ # JPA 엔티티 (News, Recruit, Inquiry 등) +│ │ ├── repository/ # Spring Data JPA +│ │ ├── service/ # 비즈니스 로직 +│ │ ├── controller/ # REST 컨트롤러 (/api/*) +│ │ └── config/ # SecurityConfig, JwtConfig +│ └── src/main/resources/ +│ └── application.yml # 포트 8082, SQLite (dev) / MySQL (prod) +└── frontend/ # React 18 + Vite + ├── package.json # react-router-dom, axios + └── src/ + ├── App.jsx # 라우터 정의 + ├── pages/ # 공개 페이지 (Home, Company, Business 등) + └── pages/admin/ # 관리자 (AdminDashboard, AdminNews 등) +``` + +## 공개 페이지 목록 + +| 경로 | 컴포넌트 | 기능 | +|------|---------|------| +| `/` | Home.jsx | 메인 | +| `/company` | Company.jsx | 회사 소개 | +| `/business` | Business.jsx | 사업 영역 | +| `/solution` | SolutionPage.jsx | GUARDiA 솔루션 | +| `/news` | NewsPage.jsx | 뉴스/공지 | +| `/recruit` | Recruit.jsx | 채용 | +| `/contact` | Contact.jsx | 문의 | +| `/guardia` | GuardiaDetail.jsx | GUARDiA 상세 | + +## 관리자 페이지 목록 + +| 경로 | 컴포넌트 | 기능 | +|------|---------|------| +| `/admin` | AdminDashboard.jsx | 대시보드 | +| `/admin/news` | AdminNews.jsx | 뉴스 CRUD | +| `/admin/recruit` | AdminRecruit.jsx | 채용 CRUD | +| `/admin/inquiry` | AdminInquiry.jsx | 문의 관리 | +| `/admin/history` | AdminHistory.jsx | 연혁 CRUD | +| `/admin/settings` | AdminSettings.jsx | 설정 | + +## 개발 원칙 + +1. **신규 DB 항목 추가 패턴**: Entity → Repository → Service → Controller → React AdminPage +2. **빌드**: `vite build --outDir C:\Temp\zioinfo-build` → Spring Boot static resources에 복사 +3. **배포**: `mvn clean package -DskipTests` → JAR → `/opt/zioinfo/app/app.jar` → `systemctl restart zioinfo` +4. **인증**: 관리자는 JWT (`/api/admin/login`), 회원은 별도 JWT + +## 팀 통신 프로토콜 + +- **수신**: guardia-fullstack-orchestrator 또는 full-stack-analyst로부터 구현 요청 +- **발신**: visual-qa-tester에게 UI 검증 요청 +- **산출물**: .java + .jsx 파일 변경 diff --git a/.claude/agents/itsm-dev.md b/.claude/agents/itsm-dev.md new file mode 100644 index 00000000..58d20d34 --- /dev/null +++ b/.claude/agents/itsm-dev.md @@ -0,0 +1,62 @@ +--- +name: itsm-dev +description: "GUARDiA ITSM FastAPI 개발 에이전트. workspace/guardia-itsm/ 경로에서 신규 라우터 추가, 모델 확장, 비즈니스 로직 구현을 담당한다. 75개 이상 라우터 구조 숙지, Ollama 연동, AES-256-GCM 암호화, JWT 인증을 준수한다." +model: opus +--- + +# ITSM Dev — GUARDiA ITSM 개발 에이전트 + +## 핵심 역할 + +`workspace/guardia-itsm/` 코드베이스에서 신기능 개발·버그 수정·성능 최적화를 수행한다. + +## 코드베이스 핵심 구조 + +``` +workspace/guardia-itsm/ +├── main.py # FastAPI 앱 진입점 (75개+ 라우터 등록) +├── models.py # SQLAlchemy ORM + Pydantic 스키마 +├── database.py # async SessionLocal, init_db +├── requirements.txt # fastapi>=0.115, sqlalchemy>=2.0, cryptography>=42 +├── core/ # 비즈니스 로직 (anomaly, chatbot, code_review 등) +├── routers/ # 75개+ API 라우터 +│ ├── auth.py # JWT 발급 /api/auth/login +│ ├── tasks.py # SR CRUD /api/tasks +│ ├── cmdb.py # CMDB /api/cmdb +│ ├── rpa.py # RPA 봇 /api/rpa +│ ├── scraping.py # 스크래핑 /api/scraping +│ ├── autonomous.py # 자율 운영 /api/autonomous +│ └── ... +└── static/ # HTML/CSS/JS SPA +``` + +## 개발 원칙 + +1. **신규 라우터 추가 패턴**: + - `routers/` 에 파일 생성 + - `main.py` import 및 `app.include_router()` 등록 + - `models.py`에 ORM 모델·Pydantic 스키마 추가 + +2. **보안 불변 규칙**: + - `ServerOut` 응답에서 `ip_addr`, `ssh_user`, `os_pw_enc` 완전 제외 + - 서버 자격증명 AES-256-GCM (`cryptography` 패키지) 암호화 필수 + - Ollama (`localhost:11434`) 외 외부 LLM API 호출 절대 금지 + - 에러 응답에 스택트레이스 미포함 — SR ID + 요약만 + +3. **DB 패턴**: `async with SessionLocal() as db:` 사용, `await db.commit()`, `await db.refresh()` + +4. **인증**: `Depends(get_current_user)` 또는 `Depends(require_admin)` 필수 + +## 테스트 경로 + +``` +workspace/guardia-itsm/tests/ +├── unit/ # pytest 단위 테스트 +└── integration/ # httpx E2E API 테스트 (BASE="http://127.0.0.1:9001") +``` + +## 팀 통신 프로토콜 + +- **수신**: full-stack-analyst 또는 guardia-fullstack-orchestrator로부터 구현 요청 +- **발신**: integration-tester에게 구현 완료 후 테스트 요청 +- **산출물**: 실제 .py 파일 코드 변경 + unit test 작성 diff --git a/.claude/agents/manager-dev.md b/.claude/agents/manager-dev.md new file mode 100644 index 00000000..1dd3804d --- /dev/null +++ b/.claude/agents/manager-dev.md @@ -0,0 +1,61 @@ +--- +name: manager-dev +description: "GUARDiA Manager 개발 에이전트. workspace/guardia-manager/ 경로에서 관리자 포털 FastAPI 백엔드·React 18 TypeScript 프론트엔드 개발을 담당한다. M-01~M-08 기능, ITSM API 연동, 네이버 클라우드 콘솔 스타일 UI를 유지한다." +model: opus +--- + +# Manager Dev — GUARDiA Manager 개발 에이전트 + +## 핵심 역할 + +`workspace/guardia-manager/` 코드베이스에서 관리자 포털 개발을 수행한다. + +## 코드베이스 핵심 구조 + +``` +workspace/guardia-manager/ +├── backend/ # Python FastAPI (포트 8002) +│ ├── main.py # 4개 라우터: system, deploy, config, llm +│ ├── core/auth.py # ITSM JWT 검증 (별도 DB 없음) +│ └── routers/ +│ ├── system.py # 서버 상태, 서비스 재시작 (systemctl) +│ ├── deploy.py # 배포 트리거, 이력 +│ ├── config.py # 설정 관리 (.env 편집) +│ └── llm.py # Ollama 상태·모델 관리 +├── frontend/ # React 18 TypeScript + Vite (포트 5175) +│ ├── src/ +│ │ ├── pages/ # M-01~M-08 기능 페이지 +│ │ ├── components/ # 공통 컴포넌트 (NCloud 스타일) +│ │ ├── hooks/ # useAuth, useITSMAPI 등 +│ │ └── api/ # API 클라이언트 (axios) +│ └── package.json +├── deploy_server.py # 웹훅 수신 서버 (포트 9999) +└── dist/ # 빌드 결과 → /var/www/manager/ +``` + +## M-01~M-08 기능 맵 + +| 코드 | 기능 | ITSM API 연동 | +|------|------|-------------| +| M-01 | 통합 운영 대시보드 | /api/dashboard, /api/system/resources | +| M-02 | 테넌트/사용자 관리 | /api/auth, /api/tenant | +| M-03 | CMDB/서버 자산 | /api/cmdb, /api/ssh | +| M-04 | 배포/CI-CD 관리 | Gitea API, /api/deploy | +| M-05 | 보안/API Key | /api/external/keys, /api/audit | +| M-06 | LLM/AI 관리 | Ollama localhost:11434 | +| M-07 | 시스템 설정 | .env 편집, Nginx | +| M-08 | 알림/리포트 | /api/report, SMTP | + +## 개발 원칙 + +1. **인증**: ITSM JWT 토큰 재사용 — `useAuth` 훅에서 `localStorage.getItem('token')` +2. **API 호출**: `axios.defaults.headers.common['Authorization'] = \`Bearer \${token}\`` +3. **UI 스타일**: 네이버 클라우드 콘솔 패턴 — 좌측 사이드바 서비스 트리 + 상단 GNB +4. **배포**: `npm run build` → `/var/www/manager/` → Nginx 서브 (포트 8090) +5. **백엔드 라우터 추가 시**: `backend/main.py`의 `app.include_router()` 등록 필수 + +## 팀 통신 프로토콜 + +- **수신**: guardia-fullstack-orchestrator 또는 full-stack-analyst로부터 구현 요청 +- **발신**: visual-qa-tester에게 UI 검증 요청 +- **산출물**: .tsx/.ts 및 .py 파일 변경 diff --git a/.claude/agents/messenger-dev.md b/.claude/agents/messenger-dev.md new file mode 100644 index 00000000..9833fd13 --- /dev/null +++ b/.claude/agents/messenger-dev.md @@ -0,0 +1,71 @@ +--- +name: messenger-dev +description: "GUARDiA Messenger React Native 앱 개발 에이전트. workspace/guardia-messenger/ 경로에서 Expo 51 + TypeScript 화면 구현, EAS 빌드, ITSM WebSocket 연동을 담당한다. EAS 빌드 실패 패턴 4종을 숙지하고 위반하지 않는다." +model: opus +--- + +# Messenger Dev — GUARDiA Messenger 개발 에이전트 + +## 핵심 역할 + +`workspace/guardia-messenger/` 코드베이스에서 React Native 화면 개발·EAS 빌드·ITSM 연동을 수행한다. + +## 코드베이스 핵심 구조 + +``` +workspace/guardia-messenger/ +├── package.json # Expo 51, React Native 0.74.5, TypeScript 5.3 +├── app.json # EAS 앱 설정 (kr.co.zioinfo.guardia) +├── eas.json # EAS 빌드 프로파일 +├── tsconfig.json +└── app/ + ├── _layout.tsx # 루트 레이아웃, 인증 초기화 + ├── (auth)/ + │ └── login.tsx # JWT 로그인 → SecureStore 저장 + └── (tabs)/ + ├── _layout.tsx # 탭 네비게이션 (6개 탭) + ├── index.tsx # 대시보드 (SR 통계, 서비스 상태) + ├── sr.tsx # SR 목록·등록 + ├── chat.tsx # AI 챗봇 (Ollama ITSM 프록시) + ├── notifications.tsx # 푸시 알림 목록 + ├── settings.tsx # 프로필·로그아웃 + ├── dr.tsx # DR 상태 (신규) + └── network.tsx # 네트워크 장비 (신규) +``` + +## ITSM API 연동 + +- 기본 URL: `https://zioinfo.co.kr:8443` (OpenNet 경유) +- 인증: JWT → `expo-secure-store`에 저장 (`SecureStore.getItemAsync('token')`) +- HTTP 클라이언트: `axios ^1.7.7` +- WebSocket: ITSM `/ws/notifications` 연결 (실시간 SR 알림) + +## EAS 빌드 금지 패턴 (위반 시 빌드 실패) + +1. `android/`, `ios/` 폴더 — **로컬 생성 금지** (`.easignore`로 EAS 제외) +2. `expo-notifications` — `app.json` 플러그인 등록 **금지** +3. `babel.config.js` — `expo-router/babel` 추가 **금지** +4. `plugins/withGradleProps.js` — `enablePngCrunchInReleaseBuilds=false` **필수 유지** + +## 화면 추가 패턴 + +```typescript +// app/(tabs)/newscreen.tsx +import React from 'react'; +import { View, Text, StyleSheet } from 'react-native'; +import axios from 'axios'; +import * as SecureStore from 'expo-secure-store'; + +export default function NewScreen() { + // ITSM API 호출: axios.get('https://zioinfo.co.kr:8443/api/...') + // ... +} +``` + +탭 네비게이션 등록: `app/(tabs)/_layout.tsx`의 `` 에 `` 추가. + +## 팀 통신 프로토콜 + +- **수신**: guardia-fullstack-orchestrator 또는 full-stack-analyst로부터 구현 요청 +- **발신**: itsm-dev에게 필요한 ITSM API 엔드포인트 추가 요청 +- **산출물**: .tsx 파일 변경 + package.json 의존성 (필요 시) diff --git a/.claude/skills/folder-cleanup-orchestrator/SKILL.md b/.claude/skills/folder-cleanup-orchestrator/SKILL.md new file mode 100644 index 00000000..e6e1f445 --- /dev/null +++ b/.claude/skills/folder-cleanup-orchestrator/SKILL.md @@ -0,0 +1,90 @@ +--- +name: folder-cleanup-orchestrator +description: "GUARDiA 루트 폴더 정리 오케스트레이터. 루트에 임시 파일·스크립트·구버전 소스가 쌓일 때 정리한다. 다음 상황에서 반드시 사용: (1) '폴더 정리', '루트 정리', '파일 정리'; (2) '스크립트 정리', '임시 파일 정리'; (3) 다시 실행, 업데이트, 보완." +--- + +# GUARDiA 폴더 정리 오케스트레이터 + +**실행 모드:** 서브 에이전트 (folder-organizer) + +## 현재 확정된 구조 (2026-06-01 기준) + +``` +C:\GUARDiA\ +├── workspace/ # 4개 프로젝트 소스 (불변) +│ ├── guardia-itsm/ +│ ├── guardia-manager/ +│ ├── guardia-messenger/ +│ └── zioinfo-web/ +├── repos/ # Gitea push용 bare repo (불변) +├── .claude/ # 하네스 (불변) +├── docs/ # 설계 문서 + .docx/.pptx +├── scripts/ # 임시 Python/JS 스크립트 +│ ├── deploy/ # deploy_*.py (26개) +│ ├── check/ # check_*.py (16개) +│ ├── push/ # push_*.py (6개) +│ ├── setup/ # setup/jenkins/install/cicd (13개) +│ └── misc/ # 기타 (21개) +├── deploy/ # 서버 배포 sh/ps1 +├── setup/ # 설치 스크립트 +├── certification/ # GS인증 서류 +├── logo/ # 로고 파일 +├── screenshot/ # UI 스크린샷 +├── design-overhaul/ # Before/After 디자인 +├── testcase/ # 테스트케이스 문서 +├── projects/ # 고객 프로젝트 소스 +├── ollama/ # Ollama 모델 설정 +├── docker/ # Docker nginx/tomcat 설정 +├── skills/ # 구버전 스킬 참조 +├── plugins/ # harness 플러그인 +├── paperclip/ # Paperclip 설정 +├── template/ # 프로젝트 템플릿 +├── _archive/ # 구버전 소스 (backend/frontend/messenger) +├── CLAUDE.md # Claude Code 진입점 (불변) +├── docker-compose*.yml # Docker 설정 파일 +├── Dockerfile # Docker 이미지 +├── start.ps1 / start.sh # 서비스 시작 스크립트 +└── zio-server-key.pem # 서버 SSH 키 +``` + +## Phase 0: 정리 대상 탐지 + +```bash +# 루트에 새로 쌓인 파일 확인 +ls C:/GUARDiA/*.py 2>/dev/null +ls C:/GUARDiA/*.js 2>/dev/null +ls C:/GUARDiA/*.log 2>/dev/null +ls C:/GUARDiA/*.docx C:/GUARDiA/*.pptx 2>/dev/null +``` + +## Phase 1: 분류 이동 규칙 + +| 패턴 | 이동 위치 | +|------|---------| +| `deploy_*.py` | `scripts/deploy/` | +| `check_*.py` | `scripts/check/` | +| `push_*.py` | `scripts/push/` | +| `setup_*.py`, `jenkins_*.py`, `install_*.py`, `cicd_*.py` | `scripts/setup/` | +| 그 외 루트 `.py` | `scripts/misc/` | +| 루트 `.js` | `scripts/misc/` | +| `*.docx`, `*.pptx`, `*.pdf` (설계문서) | `docs/` | +| `*.log` | 삭제 | +| 새 프로젝트 소스 폴더 | `workspace/` 또는 `_archive/` | + +## Phase 2: git 반영 + +```bash +cd C:/GUARDiA +git add scripts/ docs/ _archive/ -A +git commit -m "chore: 폴더 정리" +``` + +## 에러 핸들링 + +- `_archive/`에 이미 있으면 덮어쓰지 않고 버전 접미사 추가 +- `git add` 실패 시 수동 확인 요청 + +## 테스트 시나리오 + +- 정상 흐름: 루트에 `fix_xxx.py` 10개 생성 → `scripts/misc/`로 자동 분류 +- 확인: `ls C:/GUARDiA/scripts/misc/ | grep fix_` diff --git a/.claude/skills/guardia-fullstack-orchestrator/SKILL.md b/.claude/skills/guardia-fullstack-orchestrator/SKILL.md new file mode 100644 index 00000000..191d6695 --- /dev/null +++ b/.claude/skills/guardia-fullstack-orchestrator/SKILL.md @@ -0,0 +1,132 @@ +--- +name: guardia-fullstack-orchestrator +description: "GUARDiA 전체 시스템(ITSM·홈페이지·Manager·Messenger) 크로스 시스템 작업 오케스트레이터. 신기능 추가, 시스템 간 연동 수정, API 계약 변경, 통합 배포 등 여러 시스템에 걸친 작업을 조율한다. 다음 상황에서 반드시 사용: (1) '4개 시스템 분석', '전체 시스템'; (2) 여러 시스템에 걸친 기능 추가; (3) ITSM API 변경이 Manager·Messenger에 영향을 줄 때; (4) 크로스 시스템 테스트; (5) 다시 실행, 업데이트, 통합 배포." +--- + +# GUARDiA Fullstack Orchestrator + +**실행 모드:** 하이브리드 (Phase 1: 분석=서브 에이전트 / Phase 2~3: 개발=에이전트 팀 / Phase 4: QA=서브 에이전트) + +## Phase 0: 컨텍스트 확인 + +``` +1. _workspace/ 존재 여부 확인 + - 없음 → 초기 실행 + - 있음 + 사용자가 "다시 실행/업데이트" → _workspace/를 _workspace_prev/로 이동 후 새 실행 + - 있음 + 사용자가 특정 시스템만 수정 요청 → 해당 시스템 에이전트만 재호출 (부분 재실행) + +2. 작업 유형 분류: + A. 단일 시스템 작업 → 해당 dev 에이전트만 직접 호출 + B. 크로스 시스템 작업 → Phase 1~4 전체 실행 + C. 분석 요청 → full-stack-analyst만 호출 +``` + +## Phase 1: 영향 분석 (서브 에이전트) + +`full-stack-analyst` 에이전트를 호출하여: +- 변경 요청의 영향 범위 파악 (어느 시스템의 어느 파일) +- API 계약 변경 시 의존 시스템 목록 추출 +- 구현 순서 결정 (하위 의존 → 상위 의존) + +산출물: `_workspace/01_analysis.md` + +## Phase 2: 구현 (에이전트 팀) + +영향 받는 시스템 수에 따라 팀 구성: + +**단일 시스템**: 해당 에이전트만 호출 +- ITSM 변경 → `itsm-dev` +- 홈페이지 변경 → `homepage-dev` +- Manager 변경 → `manager-dev` +- Messenger 변경 → `messenger-dev` + +**크로스 시스템 (예: ITSM API 추가 + Manager/Messenger 클라이언트 추가)**: +``` +에이전트 팀 구성: + 1. itsm-dev — ITSM router/model 먼저 구현 (기반) + 2. manager-dev — ITSM 구현 완료 후 Manager 클라이언트 구현 + 3. messenger-dev — Messenger 화면/훅 구현 (manager-dev와 병렬 가능) +``` + +**구현 순서 규칙**: +1. DB 모델 변경 (models.py) → 2. ITSM 라우터 → 3. Manager API 클라이언트 → 4. Messenger 화면 + +## Phase 3: 배포 준비 (선택) + +`deploy-scripter` 에이전트를 통해: +- ITSM: `rsync workspace/guardia-itsm/ → /opt/guardia/app/` +- 홈페이지: `mvn clean package` + JAR 배포 +- Manager: `npm run build` → `/var/www/manager/` +- Messenger: EAS 빌드 트리거 + +## Phase 4: 통합 QA (서브 에이전트) + +`cross-system-qa` 에이전트를 호출하여: +- API 계약 일치 검증 +- 보안 필드 노출 검사 (`ip_addr`, `ssh_user`, `os_pw_enc`) +- 인증 흐름 검증 (JWT 공유) + +산출물: `_workspace/04_qa_report.md` + +--- + +## 시스템별 빠른 참조 + +시스템 상세 정보가 필요하면 `references/system-landscape.md`를 읽어라. + +### ITSM 신규 라우터 추가 체크리스트 + +- [ ] `workspace/guardia-itsm/routers/새파일.py` 생성 +- [ ] `workspace/guardia-itsm/main.py`에 import + `app.include_router()` 추가 +- [ ] `workspace/guardia-itsm/models.py`에 ORM 모델 + Pydantic 스키마 추가 +- [ ] `ServerOut` 응답에서 `ip_addr`, `ssh_user`, `os_pw_enc` 제외 확인 + +### Manager 신규 기능 체크리스트 + +- [ ] `workspace/guardia-manager/frontend/src/pages/` 새 페이지 생성 +- [ ] `workspace/guardia-manager/frontend/src/api/` API 클라이언트 메서드 추가 +- [ ] ITSM JWT 토큰 `Authorization: Bearer {token}` 헤더 확인 + +### Messenger 신규 화면 체크리스트 + +- [ ] `workspace/guardia-messenger/app/(tabs)/새화면.tsx` 생성 +- [ ] `workspace/guardia-messenger/app/(tabs)/_layout.tsx`에 탭 등록 +- [ ] EAS 금지 패턴 4종 위반 여부 확인 + +--- + +## 에러 핸들링 + +| 상황 | 처리 | +|------|------| +| ITSM 라우터 import 실패 | models.py 스키마 누락 확인 → itsm-dev에 재요청 | +| Manager TypeScript 타입 오류 | ITSM Pydantic 스키마와 TS 인터페이스 비교 → manager-dev 수정 | +| Messenger EAS 빌드 실패 | 금지 패턴 4종 중 위반 항목 확인 → messenger-dev 수정 | +| 보안 필드 노출 감지 | 즉시 작업 중단 → itsm-dev에 스키마 수정 요청 후 재검증 | + +--- + +## 테스트 시나리오 + +**정상 흐름**: "ITSM에 장비 모니터링 API 추가하고 Manager 대시보드와 Messenger에 연동해줘" +1. full-stack-analyst: 영향 범위 분석 → ITSM+Manager+Messenger 3개 시스템 +2. itsm-dev: `routers/monitor.py` 생성 → main.py 등록 +3. manager-dev: `/api/monitor` 호출 클라이언트 + 대시보드 위젯 +4. messenger-dev: `(tabs)/monitor.tsx` 화면 추가 +5. cross-system-qa: API shape 검증, 보안 필드 검사 + +**에러 흐름**: Manager에서 ITSM API 404 발생 +1. cross-system-qa: ITSM 라우터 엔드포인트 vs Manager API 클라이언트 URL 대조 +2. 불일치 발견 → manager-dev에 URL 수정 요청 +3. 재검증 + +--- + +## 후속 작업 지원 + +이 스킬은 다음 상황에서도 트리거된다: +- "다시 실행", "업데이트", "수정", "보완" +- "ITSM과 Manager 연동 확인" +- "Messenger 화면 추가" +- "전체 시스템 배포" +- "API 계약 검증", "보안 스캔" diff --git a/.claude/skills/guardia-fullstack-orchestrator/references/system-landscape.md b/.claude/skills/guardia-fullstack-orchestrator/references/system-landscape.md new file mode 100644 index 00000000..bf81b5d8 --- /dev/null +++ b/.claude/skills/guardia-fullstack-orchestrator/references/system-landscape.md @@ -0,0 +1,161 @@ +# GUARDiA 시스템 랜드스케이프 + +## 4개 시스템 전체 맵 + +### 1. GUARDiA ITSM (중앙 허브) + +``` +경로: workspace/guardia-itsm/ +URL: http://localhost:9001 / https://zioinfo.co.kr:8443 (OpenNet) +언어: Python 3.11 + FastAPI 0.115+ +DB: SQLite (dev) / PostgreSQL 16 (prod) +LLM: Ollama localhost:11434 (codellama:7b, llama3:8b, nomic-embed-text) +``` + +**라우터 카테고리 (75개+)** + +| 카테고리 | 라우터 | 설명 | +|---------|--------|------| +| 인증/권한 | auth, ldap, pam, otp | JWT, LDAP/AD, 특권접근, 2FA | +| SR 관리 | tasks, approvals, assign, batch | SR CRUD, 승인, 자동배정 | +| CMDB | cmdb, servers | 서버 자산, CI 관계 | +| AI | chatbot, code_review, anomaly, kb_agent, orchestrator, predictive | Ollama 연동 | +| 운영 | incidents, oncall, dr, network_devices | 인시던트, DR, 네트워크 | +| 보안 | audit, vuln_scan, siem, compliance, csap | 감사, 취약점, CSAP | +| 분석 | analytics, sla, metrics, finops, report | 대시보드, Grafana | +| 자동화 | rpa, scraping, autonomous, ssh | RPA봇, 스크래핑, SSH | +| SI 관리 | si_projects, si_wbs, si_requirements, si_issues 등 | SI 프로젝트 | +| 연동 | external_api, export_import, gateway, groupware | 외부 시스템 | +| 기관 | institutions, tenant_mgmt | 멀티테넌트 | + +**핵심 API 엔드포인트** + +``` +POST /api/auth/login → JWT 발급 +GET /api/tasks → SR 목록 +POST /api/tasks → SR 생성 +GET /api/dashboard → 대시보드 통계 +GET /api/cmdb/servers → 서버 자산 +POST /api/rpa/execute → RPA 실행 +GET /api/scraping/stats → 스크래핑 통계 +POST /api/autonomous/approve/{id} → 자율처리 승인 +WS /ws/notifications → 실시간 알림 +``` + +--- + +### 2. zioinfo-web (홈페이지) + +``` +경로: workspace/zioinfo-web/ +URL: http://localhost:8082 / https://zioinfo.co.kr:8082 +언어: Java 17 + Spring Boot 3.2.5 +DB: SQLite (dev) / MySQL (prod) +빌드: mvn clean package -DskipTests → target/zioinfo-web-1.0.0.jar +배포: /opt/zioinfo/app/app.jar → systemctl restart zioinfo +``` + +**DB 엔티티 현황** + +| 엔티티 | 테이블 | 공개 API | 관리자 API | +|--------|--------|---------|-----------| +| News | tb_news | GET /api/news | /api/admin/news | +| Recruit | tb_recruit | GET /api/recruit | /api/admin/recruit | +| Inquiry | tb_inquiry | POST /api/inquiry | /api/admin/inquiries | +| CompanyHistory | tb_company_history | GET /api/history | /api/admin/history | +| Member | tb_member | - | /api/admin/members | + +**프론트엔드 페이지 (React 18/Vite)** + +공개: Home, Company, Business, SolutionPage, GuardiaDetail, NewsPage, Recruit, Contact, Support +관리자: AdminDashboard, AdminNews, AdminRecruit, AdminInquiry, AdminHistory, AdminSettings, AdminMember + +--- + +### 3. GUARDiA Manager (관리자 포털) + +``` +경로: workspace/guardia-manager/ +URL: http://localhost:8090 (Nginx 서브) +백엔드: Python FastAPI 포트 8002 +프론트: React 18 TypeScript + Vite → /var/www/manager/ +인증: ITSM JWT 재사용 (별도 DB 없음) +``` + +**백엔드 라우터 (4개)** + +| 라우터 | 접두사 | 역할 | +|--------|--------|------| +| system.py | /api/system | 서버 상태(psutil), 서비스 제어(systemctl) | +| deploy.py | /api/deploy | 배포 트리거, 이력 | +| config.py | /api/config | .env 편집, Nginx 리로드 | +| llm.py | /api/llm | Ollama 상태·모델 관리 | + +**관리 서비스 목록** (ALLOWED_SVCS): +nginx, zioinfo, zioinfo-deploy, guardia, guardia-manager, gitea, jenkins, postgresql, ollama + +--- + +### 4. GUARDiA Messenger (모바일 앱) + +``` +경로: workspace/guardia-messenger/ +플랫폼: Android (APK) / iOS +빌드: EAS Build (eas build --platform android) +계정: EAS zioinfo / 프로젝트 ID ca2f72d6-7dda-4491-9590-7ace34b10a88 +패키지: kr.co.zioinfo.guardia +``` + +**화면 목록 (9개)** + +| 화면 | 경로 | ITSM API | +|------|------|---------| +| 로그인 | (auth)/login.tsx | POST /api/auth/login | +| 대시보드 | (tabs)/index.tsx | GET /api/dashboard | +| SR 관리 | (tabs)/sr.tsx | GET/POST /api/tasks | +| AI 챗봇 | (tabs)/chat.tsx | POST /api/chatbot/message (Ollama) | +| 알림 | (tabs)/notifications.tsx | WS /ws/notifications | +| 설정 | (tabs)/settings.tsx | GET /api/auth/me | +| DR 상태 | (tabs)/dr.tsx | GET /api/dr/status | +| 네트워크 | (tabs)/network.tsx | GET /api/network_devices | + +--- + +## 시스템 간 API 의존 관계 + +``` + ┌─────────────────────────┐ + │ GUARDiA ITSM (허브) │ + │ localhost:9001 │ + │ :8443 (OpenNet) │ + └───────────┬─────────────┘ + │ + ┌──────────────────────┼──────────────────────┐ + │ │ │ + ▼ ▼ ▼ +┌─────────────────┐ ┌─────────────────┐ ┌─────────────────────┐ +│ GUARDiA Manager │ │ Messenger (EAS) │ │ zioinfo-web (홈페이지)│ +│ :8002/:8090 │ │ Android/iOS │ │ :8082 │ +│ JWT 재사용 │ │ SecureStore JWT │ │ 독립 (연락처만) │ +└─────────────────┘ └─────────────────┘ └─────────────────────┘ +``` + +## 공유 인프라 + +| 서비스 | 포트 | 역할 | +|--------|------|------| +| Nginx | 443/8443/8082/8090/8080 | SSL 역방향 프록시 | +| PostgreSQL 16 | 5432 | ITSM 운영 DB | +| Ollama | 11434 | 온프레미스 LLM | +| Gitea | 3000/9003 | Git 저장소 | +| Jenkins | 8080/9080 | CI/CD | +| Deploy Webhook | 9999 | 자동 배포 트리거 | + +## 배포 서버 정보 + +서버 IP: 101.79.17.164 +서비스 경로: +- ITSM: `/opt/guardia/app/` +- 홈페이지: `/opt/zioinfo/app/` +- Manager: `/var/www/manager/` +- Docs: `/var/www/docs/` diff --git a/CLAUDE.md b/CLAUDE.md index 86a84d44..b9fb205d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -254,6 +254,51 @@ workspace/ --- +## 하네스: GUARDiA 풀스택 통합 + +**목표:** GUARDiA ITSM·zioinfo-web·Manager·Messenger 4개 시스템을 단일 오케스트레이터로 연결. 크로스 시스템 신기능 추가·API 계약 관리·통합 QA 자동화. + +**트리거:** 4개 시스템에 걸친 작업, ITSM API 변경 + Manager/Messenger 연동, 전체 시스템 분석, 통합 배포, 크로스 시스템 기능 추가 요청 시 `guardia-fullstack-orchestrator` 스킬을 사용하라. 단일 시스템 작업도 영향 범위 분석이 필요하면 사용하라. + +**시스템 맵:** +``` +GUARDiA ITSM (허브, :9001/:8443) + ├── GUARDiA Manager (관제, :8002/:8090) — ITSM JWT 재사용 + ├── GUARDiA Messenger (EAS APK) — ITSM API 호출 + └── zioinfo-web (홈페이지, :8082) — 독립 (문의만 연결) +``` + +**에이전트:** full-stack-analyst, itsm-dev, homepage-dev, manager-dev, messenger-dev, cross-system-qa + +**시스템 상세:** `.claude/skills/guardia-fullstack-orchestrator/references/system-landscape.md` + +**변경 이력:** +| 날짜 | 변경 내용 | 대상 | 사유 | +|------|----------|------|------| +| 2026-06-01 | 초기 하네스 구성 | 전체 | 4개 시스템 전체 분석 + 마스터 하네스 생성 | + +--- + +## 하네스: 폴더 정리 + +**목표:** 루트에 쌓이는 임시 Python 스크립트·구버전 소스·로그 파일을 용도별로 분류·이동·아카이브. + +**트리거:** 폴더 정리, 루트 정리, 파일 정리, 스크립트 정리 요청 시 `folder-cleanup-orchestrator` 스킬을 사용하라. + +**현재 구조 (2026-06-01 기준):** +``` +scripts/deploy/ (26개) scripts/check/ (16개) +scripts/push/ (6개) scripts/setup/ (13개) scripts/misc/ (21개) +_archive/ (backend/ frontend/ messenger/ 구버전) +``` + +**변경 이력:** +| 날짜 | 변경 내용 | 대상 | 사유 | +|------|----------|------|------| +| 2026-06-01 | 초기 폴더 정리 | 루트 82개 파일 → scripts/, docs/, _archive/ | 루트 산재 정리 | + +--- + ## 보안 제약 (불변) > 아래 규칙은 어떤 상황에서도 위반 불가 diff --git a/Jenkinsfile b/_archive/Jenkinsfile similarity index 100% rename from Jenkinsfile rename to _archive/Jenkinsfile diff --git a/backend/.mvn/wrapper/maven-wrapper.properties b/_archive/backend/.mvn/wrapper/maven-wrapper.properties similarity index 100% rename from backend/.mvn/wrapper/maven-wrapper.properties rename to _archive/backend/.mvn/wrapper/maven-wrapper.properties diff --git a/backend/pom.xml b/_archive/backend/pom.xml similarity index 100% rename from backend/pom.xml rename to _archive/backend/pom.xml diff --git a/backend/src/main/java/kr/co/zioinfo/web/ZioinfoWebApplication.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/ZioinfoWebApplication.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/ZioinfoWebApplication.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/ZioinfoWebApplication.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/config/DataInitializer.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/config/DataInitializer.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/config/DataInitializer.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/config/DataInitializer.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/config/SecurityConfig.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/config/SecurityConfig.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/config/SecurityConfig.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/config/SecurityConfig.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/controller/AdminController.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/controller/AdminController.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/controller/AdminController.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/controller/AdminController.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/controller/ApiController.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/controller/ApiController.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/controller/ApiController.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/controller/ApiController.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/model/AdminUser.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/model/AdminUser.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/model/AdminUser.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/model/AdminUser.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/model/Inquiry.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/model/Inquiry.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/model/Inquiry.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/model/Inquiry.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/model/News.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/model/News.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/model/News.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/model/News.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/model/Recruit.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/model/Recruit.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/model/Recruit.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/model/Recruit.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/repository/AdminUserRepository.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/repository/AdminUserRepository.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/repository/AdminUserRepository.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/repository/AdminUserRepository.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/repository/InquiryRepository.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/repository/InquiryRepository.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/repository/InquiryRepository.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/repository/InquiryRepository.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/repository/NewsRepository.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/repository/NewsRepository.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/repository/NewsRepository.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/repository/NewsRepository.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/repository/RecruitRepository.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/repository/RecruitRepository.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/repository/RecruitRepository.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/repository/RecruitRepository.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/security/JwtAuthFilter.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/security/JwtAuthFilter.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/security/JwtAuthFilter.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/security/JwtAuthFilter.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/security/JwtUtil.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/security/JwtUtil.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/security/JwtUtil.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/security/JwtUtil.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/service/InquiryService.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/service/InquiryService.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/service/InquiryService.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/service/InquiryService.java diff --git a/backend/src/main/java/kr/co/zioinfo/web/service/NewsService.java b/_archive/backend/src/main/java/kr/co/zioinfo/web/service/NewsService.java similarity index 100% rename from backend/src/main/java/kr/co/zioinfo/web/service/NewsService.java rename to _archive/backend/src/main/java/kr/co/zioinfo/web/service/NewsService.java diff --git a/backend/src/main/resources/application.yml b/_archive/backend/src/main/resources/application.yml similarity index 100% rename from backend/src/main/resources/application.yml rename to _archive/backend/src/main/resources/application.yml diff --git a/backend/src/main/resources/static/assets/AdminDashboard-B5ryl_KI.js b/_archive/backend/src/main/resources/static/assets/AdminDashboard-B5ryl_KI.js similarity index 100% rename from backend/src/main/resources/static/assets/AdminDashboard-B5ryl_KI.js rename to _archive/backend/src/main/resources/static/assets/AdminDashboard-B5ryl_KI.js diff --git a/backend/src/main/resources/static/assets/AdminInquiry-BBFBdE8S.js b/_archive/backend/src/main/resources/static/assets/AdminInquiry-BBFBdE8S.js similarity index 100% rename from backend/src/main/resources/static/assets/AdminInquiry-BBFBdE8S.js rename to _archive/backend/src/main/resources/static/assets/AdminInquiry-BBFBdE8S.js diff --git a/backend/src/main/resources/static/assets/AdminLayout-uWX9KsdF.js b/_archive/backend/src/main/resources/static/assets/AdminLayout-uWX9KsdF.js similarity index 100% rename from backend/src/main/resources/static/assets/AdminLayout-uWX9KsdF.js rename to _archive/backend/src/main/resources/static/assets/AdminLayout-uWX9KsdF.js diff --git a/backend/src/main/resources/static/assets/AdminLogin-DcRT5LbX.js b/_archive/backend/src/main/resources/static/assets/AdminLogin-DcRT5LbX.js similarity index 100% rename from backend/src/main/resources/static/assets/AdminLogin-DcRT5LbX.js rename to _archive/backend/src/main/resources/static/assets/AdminLogin-DcRT5LbX.js diff --git a/backend/src/main/resources/static/assets/AdminNews-CDSgPR9E.js b/_archive/backend/src/main/resources/static/assets/AdminNews-CDSgPR9E.js similarity index 100% rename from backend/src/main/resources/static/assets/AdminNews-CDSgPR9E.js rename to _archive/backend/src/main/resources/static/assets/AdminNews-CDSgPR9E.js diff --git a/backend/src/main/resources/static/assets/AdminRecruit-CfX4mhQb.js b/_archive/backend/src/main/resources/static/assets/AdminRecruit-CfX4mhQb.js similarity index 100% rename from backend/src/main/resources/static/assets/AdminRecruit-CfX4mhQb.js rename to _archive/backend/src/main/resources/static/assets/AdminRecruit-CfX4mhQb.js diff --git a/backend/src/main/resources/static/assets/AdminSettings-DaHEGHsg.js b/_archive/backend/src/main/resources/static/assets/AdminSettings-DaHEGHsg.js similarity index 100% rename from backend/src/main/resources/static/assets/AdminSettings-DaHEGHsg.js rename to _archive/backend/src/main/resources/static/assets/AdminSettings-DaHEGHsg.js diff --git a/backend/src/main/resources/static/assets/Business-EGnXphuY.js b/_archive/backend/src/main/resources/static/assets/Business-EGnXphuY.js similarity index 100% rename from backend/src/main/resources/static/assets/Business-EGnXphuY.js rename to _archive/backend/src/main/resources/static/assets/Business-EGnXphuY.js diff --git a/backend/src/main/resources/static/assets/Business-EM7OeA4c.css b/_archive/backend/src/main/resources/static/assets/Business-EM7OeA4c.css similarity index 100% rename from backend/src/main/resources/static/assets/Business-EM7OeA4c.css rename to _archive/backend/src/main/resources/static/assets/Business-EM7OeA4c.css diff --git a/backend/src/main/resources/static/assets/Common-BmvLh5lB.css b/_archive/backend/src/main/resources/static/assets/Common-BmvLh5lB.css similarity index 100% rename from backend/src/main/resources/static/assets/Common-BmvLh5lB.css rename to _archive/backend/src/main/resources/static/assets/Common-BmvLh5lB.css diff --git a/backend/src/main/resources/static/assets/Company-BOdWAIQ4.js b/_archive/backend/src/main/resources/static/assets/Company-BOdWAIQ4.js similarity index 100% rename from backend/src/main/resources/static/assets/Company-BOdWAIQ4.js rename to _archive/backend/src/main/resources/static/assets/Company-BOdWAIQ4.js diff --git a/backend/src/main/resources/static/assets/Company-qD6qaVvP.css b/_archive/backend/src/main/resources/static/assets/Company-qD6qaVvP.css similarity index 100% rename from backend/src/main/resources/static/assets/Company-qD6qaVvP.css rename to _archive/backend/src/main/resources/static/assets/Company-qD6qaVvP.css diff --git a/backend/src/main/resources/static/assets/Contact-C2ZwoM3_.css b/_archive/backend/src/main/resources/static/assets/Contact-C2ZwoM3_.css similarity index 100% rename from backend/src/main/resources/static/assets/Contact-C2ZwoM3_.css rename to _archive/backend/src/main/resources/static/assets/Contact-C2ZwoM3_.css diff --git a/backend/src/main/resources/static/assets/Contact-C6p_tBWi.js b/_archive/backend/src/main/resources/static/assets/Contact-C6p_tBWi.js similarity index 100% rename from backend/src/main/resources/static/assets/Contact-C6p_tBWi.js rename to _archive/backend/src/main/resources/static/assets/Contact-C6p_tBWi.js diff --git a/backend/src/main/resources/static/assets/GuardiaDetail-5Pm8bk4O.js b/_archive/backend/src/main/resources/static/assets/GuardiaDetail-5Pm8bk4O.js similarity index 100% rename from backend/src/main/resources/static/assets/GuardiaDetail-5Pm8bk4O.js rename to _archive/backend/src/main/resources/static/assets/GuardiaDetail-5Pm8bk4O.js diff --git a/backend/src/main/resources/static/assets/GuardiaDetail-Ax0ubrjA.css b/_archive/backend/src/main/resources/static/assets/GuardiaDetail-Ax0ubrjA.css similarity index 100% rename from backend/src/main/resources/static/assets/GuardiaDetail-Ax0ubrjA.css rename to _archive/backend/src/main/resources/static/assets/GuardiaDetail-Ax0ubrjA.css diff --git a/backend/src/main/resources/static/assets/Home-BC38QtTl.js b/_archive/backend/src/main/resources/static/assets/Home-BC38QtTl.js similarity index 100% rename from backend/src/main/resources/static/assets/Home-BC38QtTl.js rename to _archive/backend/src/main/resources/static/assets/Home-BC38QtTl.js diff --git a/backend/src/main/resources/static/assets/Home-jagO1aR4.css b/_archive/backend/src/main/resources/static/assets/Home-jagO1aR4.css similarity index 100% rename from backend/src/main/resources/static/assets/Home-jagO1aR4.css rename to _archive/backend/src/main/resources/static/assets/Home-jagO1aR4.css diff --git a/backend/src/main/resources/static/assets/NewsPage-BgXQ2CUT.css b/_archive/backend/src/main/resources/static/assets/NewsPage-BgXQ2CUT.css similarity index 100% rename from backend/src/main/resources/static/assets/NewsPage-BgXQ2CUT.css rename to _archive/backend/src/main/resources/static/assets/NewsPage-BgXQ2CUT.css diff --git a/backend/src/main/resources/static/assets/NewsPage-mgytOZhS.js b/_archive/backend/src/main/resources/static/assets/NewsPage-mgytOZhS.js similarity index 100% rename from backend/src/main/resources/static/assets/NewsPage-mgytOZhS.js rename to _archive/backend/src/main/resources/static/assets/NewsPage-mgytOZhS.js diff --git a/backend/src/main/resources/static/assets/NotFound-KZZDVQMb.js b/_archive/backend/src/main/resources/static/assets/NotFound-KZZDVQMb.js similarity index 100% rename from backend/src/main/resources/static/assets/NotFound-KZZDVQMb.js rename to _archive/backend/src/main/resources/static/assets/NotFound-KZZDVQMb.js diff --git a/backend/src/main/resources/static/assets/Recruit-CbW65yqF.css b/_archive/backend/src/main/resources/static/assets/Recruit-CbW65yqF.css similarity index 100% rename from backend/src/main/resources/static/assets/Recruit-CbW65yqF.css rename to _archive/backend/src/main/resources/static/assets/Recruit-CbW65yqF.css diff --git a/backend/src/main/resources/static/assets/Recruit-DlKGM6KQ.js b/_archive/backend/src/main/resources/static/assets/Recruit-DlKGM6KQ.js similarity index 100% rename from backend/src/main/resources/static/assets/Recruit-DlKGM6KQ.js rename to _archive/backend/src/main/resources/static/assets/Recruit-DlKGM6KQ.js diff --git a/backend/src/main/resources/static/assets/SolutionPage-C7_Wcm8g.css b/_archive/backend/src/main/resources/static/assets/SolutionPage-C7_Wcm8g.css similarity index 100% rename from backend/src/main/resources/static/assets/SolutionPage-C7_Wcm8g.css rename to _archive/backend/src/main/resources/static/assets/SolutionPage-C7_Wcm8g.css diff --git a/backend/src/main/resources/static/assets/SolutionPage-Da0Vpoc-.js b/_archive/backend/src/main/resources/static/assets/SolutionPage-Da0Vpoc-.js similarity index 100% rename from backend/src/main/resources/static/assets/SolutionPage-Da0Vpoc-.js rename to _archive/backend/src/main/resources/static/assets/SolutionPage-Da0Vpoc-.js diff --git a/backend/src/main/resources/static/assets/Support-C5QVP1gW.js b/_archive/backend/src/main/resources/static/assets/Support-C5QVP1gW.js similarity index 100% rename from backend/src/main/resources/static/assets/Support-C5QVP1gW.js rename to _archive/backend/src/main/resources/static/assets/Support-C5QVP1gW.js diff --git a/backend/src/main/resources/static/assets/Support-DvGESosS.css b/_archive/backend/src/main/resources/static/assets/Support-DvGESosS.css similarity index 100% rename from backend/src/main/resources/static/assets/Support-DvGESosS.css rename to _archive/backend/src/main/resources/static/assets/Support-DvGESosS.css diff --git a/backend/src/main/resources/static/assets/admin-BHL-7hu0.css b/_archive/backend/src/main/resources/static/assets/admin-BHL-7hu0.css similarity index 100% rename from backend/src/main/resources/static/assets/admin-BHL-7hu0.css rename to _archive/backend/src/main/resources/static/assets/admin-BHL-7hu0.css diff --git a/backend/src/main/resources/static/assets/index-ChpGil2q.js b/_archive/backend/src/main/resources/static/assets/index-ChpGil2q.js similarity index 100% rename from backend/src/main/resources/static/assets/index-ChpGil2q.js rename to _archive/backend/src/main/resources/static/assets/index-ChpGil2q.js diff --git a/backend/src/main/resources/static/assets/index-DcNlVx-A.js b/_archive/backend/src/main/resources/static/assets/index-DcNlVx-A.js similarity index 100% rename from backend/src/main/resources/static/assets/index-DcNlVx-A.js rename to _archive/backend/src/main/resources/static/assets/index-DcNlVx-A.js diff --git a/backend/src/main/resources/static/assets/index-Dk81znn6.css b/_archive/backend/src/main/resources/static/assets/index-Dk81znn6.css similarity index 100% rename from backend/src/main/resources/static/assets/index-Dk81znn6.css rename to _archive/backend/src/main/resources/static/assets/index-Dk81znn6.css diff --git a/backend/src/main/resources/static/favicon.ico b/_archive/backend/src/main/resources/static/favicon.ico similarity index 100% rename from backend/src/main/resources/static/favicon.ico rename to _archive/backend/src/main/resources/static/favicon.ico diff --git a/backend/src/main/resources/static/index.html b/_archive/backend/src/main/resources/static/index.html similarity index 100% rename from backend/src/main/resources/static/index.html rename to _archive/backend/src/main/resources/static/index.html diff --git a/backend/src/main/resources/static/logo-white.png b/_archive/backend/src/main/resources/static/logo-white.png similarity index 100% rename from backend/src/main/resources/static/logo-white.png rename to _archive/backend/src/main/resources/static/logo-white.png diff --git a/backend/src/main/resources/static/logo.png b/_archive/backend/src/main/resources/static/logo.png similarity index 100% rename from backend/src/main/resources/static/logo.png rename to _archive/backend/src/main/resources/static/logo.png diff --git a/backend/src/main/resources/static/screenshots/01_dashboard.png b/_archive/backend/src/main/resources/static/screenshots/01_dashboard.png similarity index 100% rename from backend/src/main/resources/static/screenshots/01_dashboard.png rename to _archive/backend/src/main/resources/static/screenshots/01_dashboard.png diff --git a/backend/src/main/resources/static/screenshots/01_home.png b/_archive/backend/src/main/resources/static/screenshots/01_home.png similarity index 100% rename from backend/src/main/resources/static/screenshots/01_home.png rename to _archive/backend/src/main/resources/static/screenshots/01_home.png diff --git a/backend/src/main/resources/static/screenshots/01_home_viewport.png b/_archive/backend/src/main/resources/static/screenshots/01_home_viewport.png similarity index 100% rename from backend/src/main/resources/static/screenshots/01_home_viewport.png rename to _archive/backend/src/main/resources/static/screenshots/01_home_viewport.png diff --git a/backend/src/main/resources/static/screenshots/02_guardia.png b/_archive/backend/src/main/resources/static/screenshots/02_guardia.png similarity index 100% rename from backend/src/main/resources/static/screenshots/02_guardia.png rename to _archive/backend/src/main/resources/static/screenshots/02_guardia.png diff --git a/backend/src/main/resources/static/screenshots/02_guardia_viewport.png b/_archive/backend/src/main/resources/static/screenshots/02_guardia_viewport.png similarity index 100% rename from backend/src/main/resources/static/screenshots/02_guardia_viewport.png rename to _archive/backend/src/main/resources/static/screenshots/02_guardia_viewport.png diff --git a/backend/src/main/resources/static/screenshots/02_sr_list.png b/_archive/backend/src/main/resources/static/screenshots/02_sr_list.png similarity index 100% rename from backend/src/main/resources/static/screenshots/02_sr_list.png rename to _archive/backend/src/main/resources/static/screenshots/02_sr_list.png diff --git a/backend/src/main/resources/static/screenshots/03_company.png b/_archive/backend/src/main/resources/static/screenshots/03_company.png similarity index 100% rename from backend/src/main/resources/static/screenshots/03_company.png rename to _archive/backend/src/main/resources/static/screenshots/03_company.png diff --git a/backend/src/main/resources/static/screenshots/03_company_viewport.png b/_archive/backend/src/main/resources/static/screenshots/03_company_viewport.png similarity index 100% rename from backend/src/main/resources/static/screenshots/03_company_viewport.png rename to _archive/backend/src/main/resources/static/screenshots/03_company_viewport.png diff --git a/backend/src/main/resources/static/screenshots/03_si_project.png b/_archive/backend/src/main/resources/static/screenshots/03_si_project.png similarity index 100% rename from backend/src/main/resources/static/screenshots/03_si_project.png rename to _archive/backend/src/main/resources/static/screenshots/03_si_project.png diff --git a/backend/src/main/resources/static/screenshots/04_contact.png b/_archive/backend/src/main/resources/static/screenshots/04_contact.png similarity index 100% rename from backend/src/main/resources/static/screenshots/04_contact.png rename to _archive/backend/src/main/resources/static/screenshots/04_contact.png diff --git a/backend/src/main/resources/static/screenshots/04_contact_viewport.png b/_archive/backend/src/main/resources/static/screenshots/04_contact_viewport.png similarity index 100% rename from backend/src/main/resources/static/screenshots/04_contact_viewport.png rename to _archive/backend/src/main/resources/static/screenshots/04_contact_viewport.png diff --git a/backend/src/main/resources/static/screenshots/04_incidents.png b/_archive/backend/src/main/resources/static/screenshots/04_incidents.png similarity index 100% rename from backend/src/main/resources/static/screenshots/04_incidents.png rename to _archive/backend/src/main/resources/static/screenshots/04_incidents.png diff --git a/backend/src/main/resources/static/screenshots/05_agents.png b/_archive/backend/src/main/resources/static/screenshots/05_agents.png similarity index 100% rename from backend/src/main/resources/static/screenshots/05_agents.png rename to _archive/backend/src/main/resources/static/screenshots/05_agents.png diff --git a/backend/src/main/resources/static/screenshots/05_news.png b/_archive/backend/src/main/resources/static/screenshots/05_news.png similarity index 100% rename from backend/src/main/resources/static/screenshots/05_news.png rename to _archive/backend/src/main/resources/static/screenshots/05_news.png diff --git a/backend/src/main/resources/static/screenshots/05_news_viewport.png b/_archive/backend/src/main/resources/static/screenshots/05_news_viewport.png similarity index 100% rename from backend/src/main/resources/static/screenshots/05_news_viewport.png rename to _archive/backend/src/main/resources/static/screenshots/05_news_viewport.png diff --git a/backend/src/main/resources/static/screenshots/06_license.png b/_archive/backend/src/main/resources/static/screenshots/06_license.png similarity index 100% rename from backend/src/main/resources/static/screenshots/06_license.png rename to _archive/backend/src/main/resources/static/screenshots/06_license.png diff --git a/backend/src/main/resources/static/screenshots/06_mobile_home.png b/_archive/backend/src/main/resources/static/screenshots/06_mobile_home.png similarity index 100% rename from backend/src/main/resources/static/screenshots/06_mobile_home.png rename to _archive/backend/src/main/resources/static/screenshots/06_mobile_home.png diff --git a/backend/src/main/resources/static/screenshots/all-pages-result.json b/_archive/backend/src/main/resources/static/screenshots/all-pages-result.json similarity index 100% rename from backend/src/main/resources/static/screenshots/all-pages-result.json rename to _archive/backend/src/main/resources/static/screenshots/all-pages-result.json diff --git a/backend/src/main/resources/static/screenshots/business_partner.png b/_archive/backend/src/main/resources/static/screenshots/business_partner.png similarity index 100% rename from backend/src/main/resources/static/screenshots/business_partner.png rename to _archive/backend/src/main/resources/static/screenshots/business_partner.png diff --git a/backend/src/main/resources/static/screenshots/business_ref.png b/_archive/backend/src/main/resources/static/screenshots/business_ref.png similarity index 100% rename from backend/src/main/resources/static/screenshots/business_ref.png rename to _archive/backend/src/main/resources/static/screenshots/business_ref.png diff --git a/backend/src/main/resources/static/screenshots/company_ci.png b/_archive/backend/src/main/resources/static/screenshots/company_ci.png similarity index 100% rename from backend/src/main/resources/static/screenshots/company_ci.png rename to _archive/backend/src/main/resources/static/screenshots/company_ci.png diff --git a/backend/src/main/resources/static/screenshots/company_greeting.png b/_archive/backend/src/main/resources/static/screenshots/company_greeting.png similarity index 100% rename from backend/src/main/resources/static/screenshots/company_greeting.png rename to _archive/backend/src/main/resources/static/screenshots/company_greeting.png diff --git a/backend/src/main/resources/static/screenshots/company_history.png b/_archive/backend/src/main/resources/static/screenshots/company_history.png similarity index 100% rename from backend/src/main/resources/static/screenshots/company_history.png rename to _archive/backend/src/main/resources/static/screenshots/company_history.png diff --git a/backend/src/main/resources/static/screenshots/company_location.png b/_archive/backend/src/main/resources/static/screenshots/company_location.png similarity index 100% rename from backend/src/main/resources/static/screenshots/company_location.png rename to _archive/backend/src/main/resources/static/screenshots/company_location.png diff --git a/backend/src/main/resources/static/screenshots/company_org.png b/_archive/backend/src/main/resources/static/screenshots/company_org.png similarity index 100% rename from backend/src/main/resources/static/screenshots/company_org.png rename to _archive/backend/src/main/resources/static/screenshots/company_org.png diff --git a/backend/src/main/resources/static/screenshots/guardia.png b/_archive/backend/src/main/resources/static/screenshots/guardia.png similarity index 100% rename from backend/src/main/resources/static/screenshots/guardia.png rename to _archive/backend/src/main/resources/static/screenshots/guardia.png diff --git a/backend/src/main/resources/static/screenshots/home.png b/_archive/backend/src/main/resources/static/screenshots/home.png similarity index 100% rename from backend/src/main/resources/static/screenshots/home.png rename to _archive/backend/src/main/resources/static/screenshots/home.png diff --git a/backend/src/main/resources/static/screenshots/news_blog.png b/_archive/backend/src/main/resources/static/screenshots/news_blog.png similarity index 100% rename from backend/src/main/resources/static/screenshots/news_blog.png rename to _archive/backend/src/main/resources/static/screenshots/news_blog.png diff --git a/backend/src/main/resources/static/screenshots/news_newsroom.png b/_archive/backend/src/main/resources/static/screenshots/news_newsroom.png similarity index 100% rename from backend/src/main/resources/static/screenshots/news_newsroom.png rename to _archive/backend/src/main/resources/static/screenshots/news_newsroom.png diff --git a/backend/src/main/resources/static/screenshots/recruit_apply.png b/_archive/backend/src/main/resources/static/screenshots/recruit_apply.png similarity index 100% rename from backend/src/main/resources/static/screenshots/recruit_apply.png rename to _archive/backend/src/main/resources/static/screenshots/recruit_apply.png diff --git a/backend/src/main/resources/static/screenshots/recruit_jobs.png b/_archive/backend/src/main/resources/static/screenshots/recruit_jobs.png similarity index 100% rename from backend/src/main/resources/static/screenshots/recruit_jobs.png rename to _archive/backend/src/main/resources/static/screenshots/recruit_jobs.png diff --git a/backend/src/main/resources/static/screenshots/recruit_welfare.png b/_archive/backend/src/main/resources/static/screenshots/recruit_welfare.png similarity index 100% rename from backend/src/main/resources/static/screenshots/recruit_welfare.png rename to _archive/backend/src/main/resources/static/screenshots/recruit_welfare.png diff --git a/backend/src/main/resources/static/screenshots/solution_bi.png b/_archive/backend/src/main/resources/static/screenshots/solution_bi.png similarity index 100% rename from backend/src/main/resources/static/screenshots/solution_bi.png rename to _archive/backend/src/main/resources/static/screenshots/solution_bi.png diff --git a/backend/src/main/resources/static/screenshots/solution_crm.png b/_archive/backend/src/main/resources/static/screenshots/solution_crm.png similarity index 100% rename from backend/src/main/resources/static/screenshots/solution_crm.png rename to _archive/backend/src/main/resources/static/screenshots/solution_crm.png diff --git a/backend/src/main/resources/static/screenshots/solution_erp.png b/_archive/backend/src/main/resources/static/screenshots/solution_erp.png similarity index 100% rename from backend/src/main/resources/static/screenshots/solution_erp.png rename to _archive/backend/src/main/resources/static/screenshots/solution_erp.png diff --git a/backend/src/main/resources/static/screenshots/support_catalog.png b/_archive/backend/src/main/resources/static/screenshots/support_catalog.png similarity index 100% rename from backend/src/main/resources/static/screenshots/support_catalog.png rename to _archive/backend/src/main/resources/static/screenshots/support_catalog.png diff --git a/backend/src/main/resources/static/screenshots/support_contact.png b/_archive/backend/src/main/resources/static/screenshots/support_contact.png similarity index 100% rename from backend/src/main/resources/static/screenshots/support_contact.png rename to _archive/backend/src/main/resources/static/screenshots/support_contact.png diff --git a/backend/src/main/resources/static/screenshots/support_faq.png b/_archive/backend/src/main/resources/static/screenshots/support_faq.png similarity index 100% rename from backend/src/main/resources/static/screenshots/support_faq.png rename to _archive/backend/src/main/resources/static/screenshots/support_faq.png diff --git a/backend/src/main/resources/static/screenshots/support_notice.png b/_archive/backend/src/main/resources/static/screenshots/support_notice.png similarity index 100% rename from backend/src/main/resources/static/screenshots/support_notice.png rename to _archive/backend/src/main/resources/static/screenshots/support_notice.png diff --git a/backend/src/main/resources/static/screenshots/test-result.json b/_archive/backend/src/main/resources/static/screenshots/test-result.json similarity index 100% rename from backend/src/main/resources/static/screenshots/test-result.json rename to _archive/backend/src/main/resources/static/screenshots/test-result.json diff --git a/frontend/index.html b/_archive/frontend/index.html similarity index 100% rename from frontend/index.html rename to _archive/frontend/index.html diff --git a/frontend/package-lock.json b/_archive/frontend/package-lock.json similarity index 100% rename from frontend/package-lock.json rename to _archive/frontend/package-lock.json diff --git a/frontend/package.json b/_archive/frontend/package.json similarity index 100% rename from frontend/package.json rename to _archive/frontend/package.json diff --git a/frontend/public/favicon.ico b/_archive/frontend/public/favicon.ico similarity index 100% rename from frontend/public/favicon.ico rename to _archive/frontend/public/favicon.ico diff --git a/frontend/public/index.html b/_archive/frontend/public/index.html similarity index 100% rename from frontend/public/index.html rename to _archive/frontend/public/index.html diff --git a/frontend/public/logo-white.png b/_archive/frontend/public/logo-white.png similarity index 100% rename from frontend/public/logo-white.png rename to _archive/frontend/public/logo-white.png diff --git a/frontend/public/logo.png b/_archive/frontend/public/logo.png similarity index 100% rename from frontend/public/logo.png rename to _archive/frontend/public/logo.png diff --git a/frontend/public/screenshots/01_dashboard.png b/_archive/frontend/public/screenshots/01_dashboard.png similarity index 100% rename from frontend/public/screenshots/01_dashboard.png rename to _archive/frontend/public/screenshots/01_dashboard.png diff --git a/frontend/public/screenshots/01_home.png b/_archive/frontend/public/screenshots/01_home.png similarity index 100% rename from frontend/public/screenshots/01_home.png rename to _archive/frontend/public/screenshots/01_home.png diff --git a/frontend/public/screenshots/01_home_viewport.png b/_archive/frontend/public/screenshots/01_home_viewport.png similarity index 100% rename from frontend/public/screenshots/01_home_viewport.png rename to _archive/frontend/public/screenshots/01_home_viewport.png diff --git a/frontend/public/screenshots/02_guardia.png b/_archive/frontend/public/screenshots/02_guardia.png similarity index 100% rename from frontend/public/screenshots/02_guardia.png rename to _archive/frontend/public/screenshots/02_guardia.png diff --git a/frontend/public/screenshots/02_guardia_viewport.png b/_archive/frontend/public/screenshots/02_guardia_viewport.png similarity index 100% rename from frontend/public/screenshots/02_guardia_viewport.png rename to _archive/frontend/public/screenshots/02_guardia_viewport.png diff --git a/frontend/public/screenshots/02_sr_list.png b/_archive/frontend/public/screenshots/02_sr_list.png similarity index 100% rename from frontend/public/screenshots/02_sr_list.png rename to _archive/frontend/public/screenshots/02_sr_list.png diff --git a/frontend/public/screenshots/03_company.png b/_archive/frontend/public/screenshots/03_company.png similarity index 100% rename from frontend/public/screenshots/03_company.png rename to _archive/frontend/public/screenshots/03_company.png diff --git a/frontend/public/screenshots/03_company_viewport.png b/_archive/frontend/public/screenshots/03_company_viewport.png similarity index 100% rename from frontend/public/screenshots/03_company_viewport.png rename to _archive/frontend/public/screenshots/03_company_viewport.png diff --git a/frontend/public/screenshots/03_si_project.png b/_archive/frontend/public/screenshots/03_si_project.png similarity index 100% rename from frontend/public/screenshots/03_si_project.png rename to _archive/frontend/public/screenshots/03_si_project.png diff --git a/frontend/public/screenshots/04_contact.png b/_archive/frontend/public/screenshots/04_contact.png similarity index 100% rename from frontend/public/screenshots/04_contact.png rename to _archive/frontend/public/screenshots/04_contact.png diff --git a/frontend/public/screenshots/04_contact_viewport.png b/_archive/frontend/public/screenshots/04_contact_viewport.png similarity index 100% rename from frontend/public/screenshots/04_contact_viewport.png rename to _archive/frontend/public/screenshots/04_contact_viewport.png diff --git a/frontend/public/screenshots/04_incidents.png b/_archive/frontend/public/screenshots/04_incidents.png similarity index 100% rename from frontend/public/screenshots/04_incidents.png rename to _archive/frontend/public/screenshots/04_incidents.png diff --git a/frontend/public/screenshots/05_agents.png b/_archive/frontend/public/screenshots/05_agents.png similarity index 100% rename from frontend/public/screenshots/05_agents.png rename to _archive/frontend/public/screenshots/05_agents.png diff --git a/frontend/public/screenshots/05_news.png b/_archive/frontend/public/screenshots/05_news.png similarity index 100% rename from frontend/public/screenshots/05_news.png rename to _archive/frontend/public/screenshots/05_news.png diff --git a/frontend/public/screenshots/05_news_viewport.png b/_archive/frontend/public/screenshots/05_news_viewport.png similarity index 100% rename from frontend/public/screenshots/05_news_viewport.png rename to _archive/frontend/public/screenshots/05_news_viewport.png diff --git a/frontend/public/screenshots/06_license.png b/_archive/frontend/public/screenshots/06_license.png similarity index 100% rename from frontend/public/screenshots/06_license.png rename to _archive/frontend/public/screenshots/06_license.png diff --git a/frontend/public/screenshots/06_mobile_home.png b/_archive/frontend/public/screenshots/06_mobile_home.png similarity index 100% rename from frontend/public/screenshots/06_mobile_home.png rename to _archive/frontend/public/screenshots/06_mobile_home.png diff --git a/frontend/public/screenshots/all-pages-result.json b/_archive/frontend/public/screenshots/all-pages-result.json similarity index 100% rename from frontend/public/screenshots/all-pages-result.json rename to _archive/frontend/public/screenshots/all-pages-result.json diff --git a/frontend/public/screenshots/business_partner.png b/_archive/frontend/public/screenshots/business_partner.png similarity index 100% rename from frontend/public/screenshots/business_partner.png rename to _archive/frontend/public/screenshots/business_partner.png diff --git a/frontend/public/screenshots/business_ref.png b/_archive/frontend/public/screenshots/business_ref.png similarity index 100% rename from frontend/public/screenshots/business_ref.png rename to _archive/frontend/public/screenshots/business_ref.png diff --git a/frontend/public/screenshots/company_ci.png b/_archive/frontend/public/screenshots/company_ci.png similarity index 100% rename from frontend/public/screenshots/company_ci.png rename to _archive/frontend/public/screenshots/company_ci.png diff --git a/frontend/public/screenshots/company_greeting.png b/_archive/frontend/public/screenshots/company_greeting.png similarity index 100% rename from frontend/public/screenshots/company_greeting.png rename to _archive/frontend/public/screenshots/company_greeting.png diff --git a/frontend/public/screenshots/company_history.png b/_archive/frontend/public/screenshots/company_history.png similarity index 100% rename from frontend/public/screenshots/company_history.png rename to _archive/frontend/public/screenshots/company_history.png diff --git a/frontend/public/screenshots/company_location.png b/_archive/frontend/public/screenshots/company_location.png similarity index 100% rename from frontend/public/screenshots/company_location.png rename to _archive/frontend/public/screenshots/company_location.png diff --git a/frontend/public/screenshots/company_org.png b/_archive/frontend/public/screenshots/company_org.png similarity index 100% rename from frontend/public/screenshots/company_org.png rename to _archive/frontend/public/screenshots/company_org.png diff --git a/frontend/public/screenshots/guardia.png b/_archive/frontend/public/screenshots/guardia.png similarity index 100% rename from frontend/public/screenshots/guardia.png rename to _archive/frontend/public/screenshots/guardia.png diff --git a/frontend/public/screenshots/home.png b/_archive/frontend/public/screenshots/home.png similarity index 100% rename from frontend/public/screenshots/home.png rename to _archive/frontend/public/screenshots/home.png diff --git a/frontend/public/screenshots/news_blog.png b/_archive/frontend/public/screenshots/news_blog.png similarity index 100% rename from frontend/public/screenshots/news_blog.png rename to _archive/frontend/public/screenshots/news_blog.png diff --git a/frontend/public/screenshots/news_newsroom.png b/_archive/frontend/public/screenshots/news_newsroom.png similarity index 100% rename from frontend/public/screenshots/news_newsroom.png rename to _archive/frontend/public/screenshots/news_newsroom.png diff --git a/frontend/public/screenshots/recruit_apply.png b/_archive/frontend/public/screenshots/recruit_apply.png similarity index 100% rename from frontend/public/screenshots/recruit_apply.png rename to _archive/frontend/public/screenshots/recruit_apply.png diff --git a/frontend/public/screenshots/recruit_jobs.png b/_archive/frontend/public/screenshots/recruit_jobs.png similarity index 100% rename from frontend/public/screenshots/recruit_jobs.png rename to _archive/frontend/public/screenshots/recruit_jobs.png diff --git a/frontend/public/screenshots/recruit_welfare.png b/_archive/frontend/public/screenshots/recruit_welfare.png similarity index 100% rename from frontend/public/screenshots/recruit_welfare.png rename to _archive/frontend/public/screenshots/recruit_welfare.png diff --git a/frontend/public/screenshots/solution_bi.png b/_archive/frontend/public/screenshots/solution_bi.png similarity index 100% rename from frontend/public/screenshots/solution_bi.png rename to _archive/frontend/public/screenshots/solution_bi.png diff --git a/frontend/public/screenshots/solution_crm.png b/_archive/frontend/public/screenshots/solution_crm.png similarity index 100% rename from frontend/public/screenshots/solution_crm.png rename to _archive/frontend/public/screenshots/solution_crm.png diff --git a/frontend/public/screenshots/solution_erp.png b/_archive/frontend/public/screenshots/solution_erp.png similarity index 100% rename from frontend/public/screenshots/solution_erp.png rename to _archive/frontend/public/screenshots/solution_erp.png diff --git a/frontend/public/screenshots/support_catalog.png b/_archive/frontend/public/screenshots/support_catalog.png similarity index 100% rename from frontend/public/screenshots/support_catalog.png rename to _archive/frontend/public/screenshots/support_catalog.png diff --git a/frontend/public/screenshots/support_contact.png b/_archive/frontend/public/screenshots/support_contact.png similarity index 100% rename from frontend/public/screenshots/support_contact.png rename to _archive/frontend/public/screenshots/support_contact.png diff --git a/frontend/public/screenshots/support_faq.png b/_archive/frontend/public/screenshots/support_faq.png similarity index 100% rename from frontend/public/screenshots/support_faq.png rename to _archive/frontend/public/screenshots/support_faq.png diff --git a/frontend/public/screenshots/support_notice.png b/_archive/frontend/public/screenshots/support_notice.png similarity index 100% rename from frontend/public/screenshots/support_notice.png rename to _archive/frontend/public/screenshots/support_notice.png diff --git a/frontend/public/screenshots/test-result.json b/_archive/frontend/public/screenshots/test-result.json similarity index 100% rename from frontend/public/screenshots/test-result.json rename to _archive/frontend/public/screenshots/test-result.json diff --git a/frontend/src/App.jsx b/_archive/frontend/src/App.jsx similarity index 100% rename from frontend/src/App.jsx rename to _archive/frontend/src/App.jsx diff --git a/frontend/src/components/layout/Footer.css b/_archive/frontend/src/components/layout/Footer.css similarity index 100% rename from frontend/src/components/layout/Footer.css rename to _archive/frontend/src/components/layout/Footer.css diff --git a/frontend/src/components/layout/Footer.jsx b/_archive/frontend/src/components/layout/Footer.jsx similarity index 100% rename from frontend/src/components/layout/Footer.jsx rename to _archive/frontend/src/components/layout/Footer.jsx diff --git a/frontend/src/components/layout/Header.css b/_archive/frontend/src/components/layout/Header.css similarity index 100% rename from frontend/src/components/layout/Header.css rename to _archive/frontend/src/components/layout/Header.css diff --git a/frontend/src/components/layout/Header.jsx b/_archive/frontend/src/components/layout/Header.jsx similarity index 100% rename from frontend/src/components/layout/Header.jsx rename to _archive/frontend/src/components/layout/Header.jsx diff --git a/frontend/src/main.jsx b/_archive/frontend/src/main.jsx similarity index 100% rename from frontend/src/main.jsx rename to _archive/frontend/src/main.jsx diff --git a/frontend/src/pages/Business.css b/_archive/frontend/src/pages/Business.css similarity index 100% rename from frontend/src/pages/Business.css rename to _archive/frontend/src/pages/Business.css diff --git a/frontend/src/pages/Business.jsx b/_archive/frontend/src/pages/Business.jsx similarity index 100% rename from frontend/src/pages/Business.jsx rename to _archive/frontend/src/pages/Business.jsx diff --git a/frontend/src/pages/Common.css b/_archive/frontend/src/pages/Common.css similarity index 99% rename from frontend/src/pages/Common.css rename to _archive/frontend/src/pages/Common.css index f6e49bd6..1dcf6dcb 100644 --- a/frontend/src/pages/Common.css +++ b/_archive/frontend/src/pages/Common.css @@ -4,4 +4,4 @@ padding: 60px 0; color: #fff; } .page-hero-title { font-size: 40px; font-weight: 900; margin: 8px 0 12px; } -.page-hero p { color: rgba(255,255,255,.75); font-size: 16px; } +.page-hero p { color: rgba(255,255,255,.75); font-size: 16px; } diff --git a/frontend/src/pages/Company.css b/_archive/frontend/src/pages/Company.css similarity index 100% rename from frontend/src/pages/Company.css rename to _archive/frontend/src/pages/Company.css diff --git a/frontend/src/pages/Company.jsx b/_archive/frontend/src/pages/Company.jsx similarity index 100% rename from frontend/src/pages/Company.jsx rename to _archive/frontend/src/pages/Company.jsx diff --git a/frontend/src/pages/Contact.css b/_archive/frontend/src/pages/Contact.css similarity index 100% rename from frontend/src/pages/Contact.css rename to _archive/frontend/src/pages/Contact.css diff --git a/frontend/src/pages/Contact.jsx b/_archive/frontend/src/pages/Contact.jsx similarity index 100% rename from frontend/src/pages/Contact.jsx rename to _archive/frontend/src/pages/Contact.jsx diff --git a/frontend/src/pages/GuardiaDetail.css b/_archive/frontend/src/pages/GuardiaDetail.css similarity index 100% rename from frontend/src/pages/GuardiaDetail.css rename to _archive/frontend/src/pages/GuardiaDetail.css diff --git a/frontend/src/pages/GuardiaDetail.jsx b/_archive/frontend/src/pages/GuardiaDetail.jsx similarity index 100% rename from frontend/src/pages/GuardiaDetail.jsx rename to _archive/frontend/src/pages/GuardiaDetail.jsx diff --git a/frontend/src/pages/Home.css b/_archive/frontend/src/pages/Home.css similarity index 100% rename from frontend/src/pages/Home.css rename to _archive/frontend/src/pages/Home.css diff --git a/frontend/src/pages/Home.jsx b/_archive/frontend/src/pages/Home.jsx similarity index 100% rename from frontend/src/pages/Home.jsx rename to _archive/frontend/src/pages/Home.jsx diff --git a/frontend/src/pages/NewsPage.css b/_archive/frontend/src/pages/NewsPage.css similarity index 100% rename from frontend/src/pages/NewsPage.css rename to _archive/frontend/src/pages/NewsPage.css diff --git a/frontend/src/pages/NewsPage.jsx b/_archive/frontend/src/pages/NewsPage.jsx similarity index 100% rename from frontend/src/pages/NewsPage.jsx rename to _archive/frontend/src/pages/NewsPage.jsx diff --git a/frontend/src/pages/NotFound.jsx b/_archive/frontend/src/pages/NotFound.jsx similarity index 99% rename from frontend/src/pages/NotFound.jsx rename to _archive/frontend/src/pages/NotFound.jsx index ae08dad6..1e215a48 100644 --- a/frontend/src/pages/NotFound.jsx +++ b/_archive/frontend/src/pages/NotFound.jsx @@ -10,4 +10,4 @@ export default function NotFound() { 홈으로 돌아가기 ); -} +} diff --git a/frontend/src/pages/Recruit.css b/_archive/frontend/src/pages/Recruit.css similarity index 100% rename from frontend/src/pages/Recruit.css rename to _archive/frontend/src/pages/Recruit.css diff --git a/frontend/src/pages/Recruit.jsx b/_archive/frontend/src/pages/Recruit.jsx similarity index 100% rename from frontend/src/pages/Recruit.jsx rename to _archive/frontend/src/pages/Recruit.jsx diff --git a/frontend/src/pages/SolutionPage.css b/_archive/frontend/src/pages/SolutionPage.css similarity index 100% rename from frontend/src/pages/SolutionPage.css rename to _archive/frontend/src/pages/SolutionPage.css diff --git a/frontend/src/pages/SolutionPage.jsx b/_archive/frontend/src/pages/SolutionPage.jsx similarity index 100% rename from frontend/src/pages/SolutionPage.jsx rename to _archive/frontend/src/pages/SolutionPage.jsx diff --git a/frontend/src/pages/Support.css b/_archive/frontend/src/pages/Support.css similarity index 100% rename from frontend/src/pages/Support.css rename to _archive/frontend/src/pages/Support.css diff --git a/frontend/src/pages/Support.jsx b/_archive/frontend/src/pages/Support.jsx similarity index 100% rename from frontend/src/pages/Support.jsx rename to _archive/frontend/src/pages/Support.jsx diff --git a/frontend/src/pages/admin/AdminDashboard.jsx b/_archive/frontend/src/pages/admin/AdminDashboard.jsx similarity index 100% rename from frontend/src/pages/admin/AdminDashboard.jsx rename to _archive/frontend/src/pages/admin/AdminDashboard.jsx diff --git a/frontend/src/pages/admin/AdminInquiry.jsx b/_archive/frontend/src/pages/admin/AdminInquiry.jsx similarity index 100% rename from frontend/src/pages/admin/AdminInquiry.jsx rename to _archive/frontend/src/pages/admin/AdminInquiry.jsx diff --git a/frontend/src/pages/admin/AdminLayout.jsx b/_archive/frontend/src/pages/admin/AdminLayout.jsx similarity index 100% rename from frontend/src/pages/admin/AdminLayout.jsx rename to _archive/frontend/src/pages/admin/AdminLayout.jsx diff --git a/frontend/src/pages/admin/AdminLogin.jsx b/_archive/frontend/src/pages/admin/AdminLogin.jsx similarity index 100% rename from frontend/src/pages/admin/AdminLogin.jsx rename to _archive/frontend/src/pages/admin/AdminLogin.jsx diff --git a/frontend/src/pages/admin/AdminNews.jsx b/_archive/frontend/src/pages/admin/AdminNews.jsx similarity index 100% rename from frontend/src/pages/admin/AdminNews.jsx rename to _archive/frontend/src/pages/admin/AdminNews.jsx diff --git a/frontend/src/pages/admin/AdminRecruit.jsx b/_archive/frontend/src/pages/admin/AdminRecruit.jsx similarity index 100% rename from frontend/src/pages/admin/AdminRecruit.jsx rename to _archive/frontend/src/pages/admin/AdminRecruit.jsx diff --git a/frontend/src/pages/admin/AdminSettings.jsx b/_archive/frontend/src/pages/admin/AdminSettings.jsx similarity index 100% rename from frontend/src/pages/admin/AdminSettings.jsx rename to _archive/frontend/src/pages/admin/AdminSettings.jsx diff --git a/frontend/src/pages/admin/admin.css b/_archive/frontend/src/pages/admin/admin.css similarity index 100% rename from frontend/src/pages/admin/admin.css rename to _archive/frontend/src/pages/admin/admin.css diff --git a/frontend/src/styles/global.css b/_archive/frontend/src/styles/global.css similarity index 100% rename from frontend/src/styles/global.css rename to _archive/frontend/src/styles/global.css diff --git a/frontend/vite.config.js b/_archive/frontend/vite.config.js similarity index 100% rename from frontend/vite.config.js rename to _archive/frontend/vite.config.js diff --git a/messenger/core/__init__.py b/_archive/messenger/core/__init__.py similarity index 100% rename from messenger/core/__init__.py rename to _archive/messenger/core/__init__.py diff --git a/messenger/core/bot.py b/_archive/messenger/core/bot.py similarity index 100% rename from messenger/core/bot.py rename to _archive/messenger/core/bot.py diff --git a/messenger/core/chatbot.py b/_archive/messenger/core/chatbot.py similarity index 100% rename from messenger/core/chatbot.py rename to _archive/messenger/core/chatbot.py diff --git a/messenger/main.py b/_archive/messenger/main.py similarity index 100% rename from messenger/main.py rename to _archive/messenger/main.py diff --git a/messenger/models/__init__.py b/_archive/messenger/models/__init__.py similarity index 100% rename from messenger/models/__init__.py rename to _archive/messenger/models/__init__.py diff --git a/messenger/models/message.py b/_archive/messenger/models/message.py similarity index 100% rename from messenger/models/message.py rename to _archive/messenger/models/message.py diff --git a/messenger/requirements.txt b/_archive/messenger/requirements.txt similarity index 100% rename from messenger/requirements.txt rename to _archive/messenger/requirements.txt diff --git a/messenger/routers/__init__.py b/_archive/messenger/routers/__init__.py similarity index 100% rename from messenger/routers/__init__.py rename to _archive/messenger/routers/__init__.py diff --git a/messenger/routers/messages.py b/_archive/messenger/routers/messages.py similarity index 100% rename from messenger/routers/messages.py rename to _archive/messenger/routers/messages.py diff --git a/messenger/routers/webhook.py b/_archive/messenger/routers/webhook.py similarity index 100% rename from messenger/routers/webhook.py rename to _archive/messenger/routers/webhook.py diff --git a/messenger/routers/ws_relay.py b/_archive/messenger/routers/ws_relay.py similarity index 100% rename from messenger/routers/ws_relay.py rename to _archive/messenger/routers/ws_relay.py diff --git a/messenger/static/app.js b/_archive/messenger/static/app.js similarity index 100% rename from messenger/static/app.js rename to _archive/messenger/static/app.js diff --git a/messenger/static/index.html b/_archive/messenger/static/index.html similarity index 100% rename from messenger/static/index.html rename to _archive/messenger/static/index.html diff --git a/messenger/static/style.css b/_archive/messenger/static/style.css similarity index 100% rename from messenger/static/style.css rename to _archive/messenger/static/style.css diff --git a/package-lock.json b/_archive/package-lock.json similarity index 100% rename from package-lock.json rename to _archive/package-lock.json diff --git a/package.json b/_archive/package.json similarity index 100% rename from package.json rename to _archive/package.json diff --git a/AI 오케스트레이터와 인간 엔지니어 간의 협업.docx b/docs/AI 오케스트레이터와 인간 엔지니어 간의 협업.docx similarity index 100% rename from AI 오케스트레이터와 인간 엔지니어 간의 협업.docx rename to docs/AI 오케스트레이터와 인간 엔지니어 간의 협업.docx diff --git a/CICD-구축건_20260309.pptx b/docs/CICD-구축건_20260309.pptx similarity index 100% rename from CICD-구축건_20260309.pptx rename to docs/CICD-구축건_20260309.pptx diff --git a/메신져.docx b/docs/메신져.docx similarity index 100% rename from 메신져.docx rename to docs/메신져.docx diff --git a/특허출원.docx b/docs/특허출원.docx similarity index 100% rename from 특허출원.docx rename to docs/특허출원.docx diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 00000000..3f013664 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,11 @@ +# scripts/ + +GUARDiA 운영 시 사용했던 일회성 Python/JS 스크립트 모음. + +| 폴더 | 설명 | +|------|------| +| deploy/ | 서버 배포 스크립트 (deploy_*.py) | +| check/ | 상태 확인 스크립트 (check_*.py) | +| push/ | Gitea push 스크립트 | +| setup/ | 서비스 초기 설정 스크립트 | +| misc/ | 기타 유틸리티 스크립트 | diff --git a/find_manager_login.py b/scripts/misc/find_manager_login.py similarity index 100% rename from find_manager_login.py rename to scripts/misc/find_manager_login.py diff --git a/fix_gitea_push.py b/scripts/misc/fix_gitea_push.py similarity index 100% rename from fix_gitea_push.py rename to scripts/misc/fix_gitea_push.py diff --git a/fix_logo_manager.py b/scripts/misc/fix_logo_manager.py similarity index 100% rename from fix_logo_manager.py rename to scripts/misc/fix_logo_manager.py diff --git a/make_dark_logo.py b/scripts/misc/make_dark_logo.py similarity index 100% rename from make_dark_logo.py rename to scripts/misc/make_dark_logo.py diff --git a/pgvector_grant.py b/scripts/misc/pgvector_grant.py similarity index 100% rename from pgvector_grant.py rename to scripts/misc/pgvector_grant.py diff --git a/pgvector_test.py b/scripts/misc/pgvector_test.py similarity index 100% rename from pgvector_test.py rename to scripts/misc/pgvector_test.py diff --git a/playwright_home.py b/scripts/misc/playwright_home.py similarity index 100% rename from playwright_home.py rename to scripts/misc/playwright_home.py diff --git a/playwright_remaining.py b/scripts/misc/playwright_remaining.py similarity index 100% rename from playwright_remaining.py rename to scripts/misc/playwright_remaining.py diff --git a/playwright_screenshots.py b/scripts/misc/playwright_screenshots.py similarity index 100% rename from playwright_screenshots.py rename to scripts/misc/playwright_screenshots.py diff --git a/scripts/misc/run_tests.py b/scripts/misc/run_tests.py new file mode 100644 index 00000000..8e3214a6 --- /dev/null +++ b/scripts/misc/run_tests.py @@ -0,0 +1,99 @@ +"""테스트 코드 배포 + 단위/통합 테스트 실행""" +import paramiko, sys, os +sys.stdout.reconfigure(encoding='utf-8', errors='replace') +from pathlib import Path + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=30) +sftp = client.open_sftp() + +def run(label, cmd, timeout=120): + print(f'\n{"="*55}\n[{label}]') + _, o, e = client.exec_command(cmd, timeout=timeout) + out = o.read().decode('utf-8', errors='replace').strip() + if out: print(out[-800:]) + return out + +# 테스트 파일 업로드 +LOCAL = Path(r'C:\GUARDiA\workspace\guardia-itsm\tests') +REMOTE = '/opt/guardia/app/tests' + +run('tests 디렉토리 생성', f'mkdir -p {REMOTE}/unit {REMOTE}/integration') + +for f in LOCAL.rglob('*.py'): + rel = f.relative_to(LOCAL).as_posix() + rp = f'{REMOTE}/{rel}' + rdir = '/'.join(rp.split('/')[:-1]) + client.exec_command(f"mkdir -p '{rdir}'") + import time; time.sleep(0.03) + sftp.put(str(f), rp) + print(f' OK {rel}') + +sftp.close() + +# pytest 설치 확인 +run('pytest + httpx 설치', """ +/opt/guardia/venv/bin/pip install pytest httpx -q && echo "OK" +""") + +# ── 단위 테스트 실행 ────────────────────────────────────────────────────────── +print('\n' + '='*55) +print('단위 테스트 실행') +run('단위 테스트', """ +cd /opt/guardia/app +/opt/guardia/venv/bin/pytest tests/unit/ \ + -v --tb=short --no-header \ + --junitxml=/tmp/unit-results.xml \ + 2>&1 +""", timeout=60) + +# ── 통합 테스트 실행 ────────────────────────────────────────────────────────── +print('\n' + '='*55) +print('통합 테스트 실행') +run('통합 테스트', """ +cd /opt/guardia/app +/opt/guardia/venv/bin/pytest tests/integration/ \ + -v --tb=short --no-header \ + --junitxml=/tmp/integration-results.xml \ + 2>&1 +""", timeout=60) + +# ── 결과 요약 ───────────────────────────────────────────────────────────────── +run('테스트 결과 요약', """ +echo "=== 단위 테스트 결과 ===" +/opt/guardia/venv/bin/python3 -c " +import xml.etree.ElementTree as ET +try: + t = ET.parse('/tmp/unit-results.xml').getroot() + total = int(t.get('tests',0)) + fail = int(t.get('failures',0)) + int(t.get('errors',0)) + skip = int(t.get('skipped',0)) + print(f' 총: {total} 성공: {total-fail-skip} 실패: {fail} 스킵: {skip}') + for tc in t.iter('testcase'): + f = tc.find('failure') + e = tc.find('error') + if f is not None or e is not None: + print(f' FAIL: {tc.get(\"classname\",\"\")}.{tc.get(\"name\",\"\")}') +except Exception as ex: print('결과 파일 없음:', ex) +" 2>/dev/null + +echo "=== 통합 테스트 결과 ===" +/opt/guardia/venv/bin/python3 -c " +import xml.etree.ElementTree as ET +try: + t = ET.parse('/tmp/integration-results.xml').getroot() + total = int(t.get('tests',0)) + fail = int(t.get('failures',0)) + int(t.get('errors',0)) + skip = int(t.get('skipped',0)) + print(f' 총: {total} 성공: {total-fail-skip} 실패: {fail} 스킵: {skip}') + for tc in t.iter('testcase'): + f = tc.find('failure') + e = tc.find('error') + if f is not None or e is not None: + print(f' FAIL: {tc.get(\"classname\",\"\")}.{tc.get(\"name\",\"\")}') +except Exception as ex: print('결과 파일 없음:', ex) +" 2>/dev/null +""") + +client.close() diff --git a/test-all-pages.js b/scripts/misc/test-all-pages.js similarity index 100% rename from test-all-pages.js rename to scripts/misc/test-all-pages.js diff --git a/test-homepage.js b/scripts/misc/test-homepage.js similarity index 100% rename from test-homepage.js rename to scripts/misc/test-homepage.js diff --git a/push_final2.py b/scripts/push/push_final2.py similarity index 100% rename from push_final2.py rename to scripts/push/push_final2.py diff --git a/push_gitea_final.py b/scripts/push/push_gitea_final.py similarity index 100% rename from push_gitea_final.py rename to scripts/push/push_gitea_final.py diff --git a/push_gitea_internal.py b/scripts/push/push_gitea_internal.py similarity index 100% rename from push_gitea_internal.py rename to scripts/push/push_gitea_internal.py diff --git a/push_remaining.py b/scripts/push/push_remaining.py similarity index 100% rename from push_remaining.py rename to scripts/push/push_remaining.py diff --git a/push_v3.py b/scripts/push/push_v3.py similarity index 100% rename from push_v3.py rename to scripts/push/push_v3.py diff --git a/push_via_server.py b/scripts/push/push_via_server.py similarity index 100% rename from push_via_server.py rename to scripts/push/push_via_server.py diff --git a/scripts/setup/cicd_full_setup.py b/scripts/setup/cicd_full_setup.py new file mode 100644 index 00000000..b7efab7f --- /dev/null +++ b/scripts/setup/cicd_full_setup.py @@ -0,0 +1,344 @@ +"""CI/CD 전체 구축: 플러그인 → Credential → Jenkinsfile → Job 생성""" +import paramiko, sys, time, json +sys.stdout.reconfigure(encoding='utf-8', errors='replace') + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=30) +sftp = client.open_sftp() + +JENKINS = 'http://127.0.0.1:9080' +AUTH = 'admin:Admin@2026!' + +def run(label, cmd, timeout=120): + print(f'\n[{label}]') + _, o, e = client.exec_command(cmd, timeout=timeout) + out = o.read().decode('utf-8', errors='replace').strip() + if out: print(out[:400]) + return out + +def jenkins_script(label, script, timeout=30): + """Jenkins Script Console 실행""" + print(f'\n[Script: {label}]') + # crumb 가져오기 + _, o, _ = client.exec_command( + f'curl -sf "{JENKINS}/crumbIssuer/api/json" -u {AUTH} 2>/dev/null', timeout=10) + crumb_data = o.read().decode('utf-8', errors='replace').strip() + try: + crumb = json.loads(crumb_data)['crumb'] + crumb_field = json.loads(crumb_data)['crumbRequestField'] + except: + crumb = '' + crumb_field = 'Jenkins-Crumb' + + escaped = script.replace("'", "'\\''") + cmd = f"""curl -sf -X POST "{JENKINS}/scriptText" -u {AUTH} \ + -H "{crumb_field}: {crumb}" \ + --data-urlencode 'script={escaped}' 2>/dev/null""" + _, o, _ = client.exec_command(cmd, timeout=timeout) + out = o.read().decode('utf-8', errors='replace').strip() + if out: print(f' {out[:200]}') + return out + +# ── 1. 플러그인 설치 ────────────────────────────────────────────────────────── +run('필수 플러그인 설치', f""" +java -jar /tmp/jenkins-cli.jar -s {JENKINS} -auth {AUTH} install-plugin \ + git workflow-aggregator pipeline-stage-view credentials-binding \ + ssh-agent nodejs timestamper ansicolor http_request junit \ + 2>&1 | tail -3 +echo "플러그인 설치 요청" +""") + +# ── 2. Credential 등록 ──────────────────────────────────────────────────────── +jenkins_script('Gitea Credential 등록', """ +import jenkins.model.* +import com.cloudbees.plugins.credentials.* +import com.cloudbees.plugins.credentials.domains.* +import com.cloudbees.plugins.credentials.impl.* + +def store = Jenkins.instance.getExtensionList( + "com.cloudbees.plugins.credentials.SystemCredentialsProvider")[0]?.getStore() + +if (store) { + // 기존 삭제 + def existing = store.getCredentials(Domain.global()).find { it.id == "gitea-zio" } + if (existing) store.removeCredentials(Domain.global(), existing) + + def cred = new UsernamePasswordCredentialsImpl( + CredentialsScope.GLOBAL, "gitea-zio", "Gitea zio account", + "zio", "Zio@Admin2026!" + ) + store.addCredentials(Domain.global(), cred) + println "gitea-zio credential 등록 완료" +} else { + println "Store 없음 - credentials 플러그인 미설치" +} +""") + +# ── 3. 글로벌 환경변수 설정 ─────────────────────────────────────────────────── +jenkins_script('글로벌 환경변수', """ +import jenkins.model.* +import hudson.slaves.* + +def instance = Jenkins.instance +def globalProps = instance.globalNodeProperties +def existing = globalProps.getAll(EnvironmentVariablesNodeProperty.class) + +EnvironmentVariablesNodeProperty prop +if (existing) { + prop = existing[0] +} else { + prop = new EnvironmentVariablesNodeProperty() + globalProps.add(prop) +} + +def env = prop.getEnvVars() +env.put("ITSM_BASE_URL", "http://127.0.0.1:9001") +env.put("GITEA_URL", "http://127.0.0.1:9003") +env.put("SERVER_HOST", "101.79.17.164") +instance.save() +println "환경변수 설정 완료" +""") + +# ── 4. Jenkinsfile 작성 ─────────────────────────────────────────────────────── +print('\n[Jenkinsfile 작성]') + +# zioinfo-web Jenkinsfile (이미 있으면 업데이트) +ZIOINFO_JF = '''pipeline { + agent any + environment { + SRC = '/opt/zioinfo/src' + JAR_DIR = '/opt/zioinfo/app' + STATIC = '/var/www/zioinfo' + MVN = '/usr/bin/mvn' + NOTIFY = "${ITSM_BASE_URL}/api/messenger/webhook" + } + options { + buildDiscarder(logRotator(numToKeepStr: '5')) + timeout(time: 20, unit: 'MINUTES') + timestamps() + } + stages { + stage('Checkout') { + steps { + checkout([ + $class: 'GitSCM', branches: scm.branches, + userRemoteConfigs: scm.userRemoteConfigs, + extensions: [[$class: 'SparseCheckoutPaths', + sparseCheckoutPaths: [[path: 'frontend'], [path: 'backend']] + ]] + ]) + } + } + stage('Frontend Build') { + steps { + dir('frontend') { + sh 'npm ci --legacy-peer-deps --prefer-offline 2>/dev/null || npm install --legacy-peer-deps' + sh 'npm run build' + } + } + } + stage('Backend Build') { + steps { + dir('backend') { + sh "${MVN} clean package -DskipTests -q" + } + } + } + stage('Deploy') { + when { branch 'main' } + steps { + sh """ + cp backend/target/*.jar ${JAR_DIR}/app.jar + cp -r backend/src/main/resources/static/. ${STATIC}/ + systemctl restart zioinfo + sleep 4 + systemctl is-active zioinfo || exit 1 + """ + } + } + } + post { + success { sh "curl -sf -X POST ${NOTIFY} -H 'Content-Type:application/json' -d '{\\"event\\":\\"build_result\\",\\"room\\":\\"ops\\",\\"success\\":true,\\"result_summary\\":\\"✅ zioinfo-web 배포 완료 #${BUILD_NUMBER}\\"}' 2>/dev/null || true" } + failure { sh "curl -sf -X POST ${NOTIFY} -H 'Content-Type:application/json' -d '{\\"event\\":\\"build_result\\",\\"room\\":\\"ops\\",\\"success\\":false,\\"result_summary\\":\\"❌ zioinfo-web 빌드 실패 #${BUILD_NUMBER}\\"}' 2>/dev/null || true" } + } +}''' + +ITSM_JF = '''pipeline { + agent any + environment { + APP = '/opt/guardia/app' + VENV = '/opt/guardia/venv' + NOTIFY = "${ITSM_BASE_URL}/api/messenger/webhook" + } + options { + buildDiscarder(logRotator(numToKeepStr: '5')) + timeout(time: 15, unit: 'MINUTES') + timestamps() + } + stages { + stage('Checkout') { steps { checkout scm } } + stage('Install') { + steps { sh "${VENV}/bin/pip install -r requirements.txt -q" } + } + stage('Test') { + when { expression { fileExists('tests/') } } + steps { + sh "${VENV}/bin/pytest tests/ -q --tb=short --junitxml=test-results.xml || true" + junit allowEmptyResults: true, testResults: 'test-results.xml' + } + } + stage('Deploy') { + when { branch 'main' } + steps { + sh """ + rsync -a --exclude=__pycache__ --exclude=.git \\ + --exclude=rpa_rules.json --exclude='*.pyc' \\ + . ${APP}/ + systemctl restart guardia + sleep 4 + systemctl is-active guardia || exit 1 + """ + } + } + } + post { + success { sh "curl -sf -X POST ${NOTIFY} -H 'Content-Type:application/json' -d '{\\"event\\":\\"build_result\\",\\"room\\":\\"ops\\",\\"success\\":true,\\"result_summary\\":\\"✅ guardia-itsm 배포 완료 #${BUILD_NUMBER}\\"}' 2>/dev/null || true" } + failure { sh "curl -sf -X POST ${NOTIFY} -H 'Content-Type:application/json' -d '{\\"event\\":\\"build_result\\",\\"room\\":\\"ops\\",\\"success\\":false,\\"result_summary\\":\\"❌ guardia-itsm 빌드 실패 #${BUILD_NUMBER}\\"}' 2>/dev/null || true" } + } +}''' + +MANAGER_JF = '''pipeline { + agent any + environment { + STATIC = '/var/www/manager' + NOTIFY = "${ITSM_BASE_URL}/api/messenger/webhook" + } + options { buildDiscarder(logRotator(numToKeepStr: '5')); timeout(time: 15, unit: 'MINUTES') } + stages { + stage('Checkout') { steps { checkout scm } } + stage('Build') { + steps { + dir('frontend') { + sh 'npm ci 2>/dev/null || npm install' + sh 'npm run build' + } + } + } + stage('Deploy') { + when { branch 'main' } + steps { + sh """ + cp -r frontend/dist/. ${STATIC}/ + systemctl restart guardia-manager 2>/dev/null || true + """ + } + } + } + post { + success { sh "curl -sf -X POST ${NOTIFY} -H 'Content-Type:application/json' -d '{\\"event\\":\\"build_result\\",\\"room\\":\\"ops\\",\\"success\\":true,\\"result_summary\\":\\"✅ guardia-manager 배포 완료\\"}' 2>/dev/null || true" } + failure { sh "curl -sf -X POST ${NOTIFY} -H 'Content-Type:application/json' -d '{\\"event\\":\\"build_result\\",\\"room\\":\\"ops\\",\\"success\\":false,\\"result_summary\\":\\"❌ guardia-manager 빌드 실패\\"}' 2>/dev/null || true" } + } +}''' + +DOCS_JF = '''pipeline { + agent any + environment { DOCS = '/var/www/docs' } + options { buildDiscarder(logRotator(numToKeepStr: '3')) } + stages { + stage('Checkout') { steps { checkout scm } } + stage('Deploy') { + when { branch 'main' } + steps { sh 'mkdir -p ${DOCS} && cp -r . ${DOCS}/' } + } + } +}''' + +# 서버의 독립 repo에 Jenkinsfile 작성 +REPO_FILES = [ + ('/opt/zioinfo/src/Jenkinsfile', ZIOINFO_JF), + ('/opt/guardia/app/Jenkinsfile', ITSM_JF), + ('/opt/manager/Jenkinsfile', MANAGER_JF), + ('/opt/docs/Jenkinsfile', DOCS_JF), +] + +for path, content in REPO_FILES: + dir_path = '/'.join(path.split('/')[:-1]) + client.exec_command(f'mkdir -p {dir_path}') + time.sleep(0.05) + try: + with sftp.open(path, 'w') as f: + f.write(content) + print(f' OK: {path}') + except Exception as ex: + print(f' SKIP {path}: {ex}') + +# 로컬 workspace에도 Jenkinsfile 저장 +import os +JF_MAP = { + r'C:\GUARDiA\workspace\zioinfo-web\Jenkinsfile': ZIOINFO_JF, + r'C:\GUARDiA\workspace\guardia-itsm\Jenkinsfile': ITSM_JF, + r'C:\GUARDiA\workspace\guardia-manager\Jenkinsfile': MANAGER_JF, + r'C:\GUARDiA\workspace\guardia-docs\Jenkinsfile': DOCS_JF, +} +for path, content in JF_MAP.items(): + with open(path, 'w', encoding='utf-8') as f: + f.write(content) + print(f' local OK: {path.split(chr(92))[-2]}/Jenkinsfile') + +# ── 5. Jenkins Job 생성 ─────────────────────────────────────────────────────── +REPOS = { + 'zioinfo-web': ('http://127.0.0.1:9003/zio/zioinfo-web.git', 'Jenkinsfile'), + 'guardia-itsm': ('http://127.0.0.1:9003/zio/guardia-itsm.git', 'Jenkinsfile'), + 'guardia-manager': ('http://127.0.0.1:9003/zio/guardia-manager.git', 'Jenkinsfile'), + 'guardia-docs': ('http://127.0.0.1:9003/zio/guardia-docs.git', 'Jenkinsfile'), +} + +for job_name, (git_url, jf_path) in REPOS.items(): + job_xml = f''' + + {job_name} CI/CD Pipeline + false + + + + + {git_url} + gitea-zio + + + + + */main + + + + {jf_path} + true + + + + + + +''' + + # Job 생성 + r = run(f'Job 생성: {job_name}', f""" + echo '{job_xml}' | java -jar /tmp/jenkins-cli.jar -s {JENKINS} -auth {AUTH} \ + create-job {job_name} 2>/dev/null \ + || java -jar /tmp/jenkins-cli.jar -s {JENKINS} -auth {AUTH} \ + update-job {job_name} << 'EOF' +{job_xml} +EOF + """) + +run('Jenkins 플러그인 재시작', f""" +java -jar /tmp/jenkins-cli.jar -s {JENKINS} -auth {AUTH} restart 2>/dev/null || true +sleep 5 +systemctl is-active jenkins +""") + +sftp.close() +client.close() +print('\n=== CI/CD 파이프라인 구축 완료 ===') diff --git a/cicd_status.py b/scripts/setup/cicd_status.py similarity index 100% rename from cicd_status.py rename to scripts/setup/cicd_status.py diff --git a/scripts/setup/jenkins_check_users.py b/scripts/setup/jenkins_check_users.py new file mode 100644 index 00000000..97c4dd79 --- /dev/null +++ b/scripts/setup/jenkins_check_users.py @@ -0,0 +1,31 @@ +import paramiko, sys +sys.stdout.reconfigure(encoding='utf-8', errors='replace') + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=15) + +def run(label, cmd): + print(f'\n[{label}]') + _, o, _ = client.exec_command(cmd, timeout=15) + print(o.read().decode('utf-8', errors='replace').strip()[:500]) + +run('사용자 폴더', 'ls /var/lib/jenkins/users/') +run('admin 설정', 'find /var/lib/jenkins/users -name "config.xml" | xargs cat 2>/dev/null | grep -E "fullName|passwordHash|id" | head -10') +run('Security 설정', 'grep -A10 "securityRealm" /var/lib/jenkins/config.xml | head -15') + +# Jenkins 임시 보안 해제 후 비밀번호 재설정 +run('보안 임시 해제', """ +cp /var/lib/jenkins/config.xml /var/lib/jenkins/config.xml.bak +sed -i 's/true<\/useSecurity>/false<\/useSecurity>/' /var/lib/jenkins/config.xml +grep "useSecurity" /var/lib/jenkins/config.xml +""") + +run('Jenkins 재시작', 'systemctl restart jenkins && sleep 8') + +run('보안 해제 후 API', """ +HTTP=$(curl -sf -o /dev/null -w "%{http_code}" http://127.0.0.1:9080/api/json 2>/dev/null) +echo "HTTP: $HTTP" +""") + +client.close() diff --git a/scripts/setup/jenkins_configure.py b/scripts/setup/jenkins_configure.py new file mode 100644 index 00000000..bef83eab --- /dev/null +++ b/scripts/setup/jenkins_configure.py @@ -0,0 +1,100 @@ +import paramiko, sys, time +sys.stdout.reconfigure(encoding='utf-8', errors='replace') + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=30) + +JENKINS = 'http://127.0.0.1:9080' +AUTH = 'admin:1q2w3e!Q' + +def run(label, cmd, timeout=120): + print(f'\n[{label}]') + _, o, e = client.exec_command(cmd, timeout=timeout) + out = o.read().decode('utf-8', errors='replace').strip() + err = e.read().decode('utf-8', errors='replace').strip() + if out: print(out[:400]) + if err: + bad = [l for l in err.splitlines() if not any(k in l.lower() for k in ['warn','info','downloading','progress'])] + if bad: print('ERR:', '\n'.join(bad[:2])) + return out + +# 1. API 접속 확인 +run('API 확인', f""" +HTTP=$(curl -sf -o /dev/null -w "%{{http_code}}" {JENKINS}/api/json -u {AUTH} 2>/dev/null) +echo "HTTP: $HTTP" +if [ "$HTTP" = "200" ]; then + curl -sf {JENKINS}/api/json -u {AUTH} 2>/dev/null | python3 -c " +import sys,json; d=json.load(sys.stdin); print('Jenkins', d.get('fullName','OK')) +" 2>/dev/null +fi +""") + +# 2. 필수 플러그인 설치 +run('필수 플러그인 설치', f""" +java -jar /tmp/jenkins-cli.jar -s {JENKINS} -auth {AUTH} install-plugin \ + git workflow-aggregator pipeline-stage-view credentials-binding \ + ssh-agent nodejs timestamper ansicolor http_request junit \ + gitea 2>&1 | tail -5 +echo "플러그인 설치 요청 완료" +""") + +# 3. Gitea Credential 등록 (Groovy Script Console) +run('Gitea Credential 등록', f""" +CRUMB=$(curl -sf "{JENKINS}/crumbIssuer/api/json" -u {AUTH} 2>/dev/null | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['crumb'])" 2>/dev/null) +echo "Crumb: $CRUMB" + +curl -sf -X POST "{JENKINS}/scriptText" -u {AUTH} \ + -H "Jenkins-Crumb: $CRUMB" \ + --data-urlencode 'script= +import jenkins.model.* +import com.cloudbees.plugins.credentials.* +import com.cloudbees.plugins.credentials.domains.* +import com.cloudbees.plugins.credentials.impl.* + +def store = Jenkins.instance.getExtensionList("com.cloudbees.plugins.credentials.SystemCredentialsProvider")[0]?.getStore() +if (store) {{ + def cred = new UsernamePasswordCredentialsImpl( + CredentialsScope.GLOBAL, "gitea-token", "Gitea zio account", + "zio", "Zio@Admin2026!" + ) + store.addCredentials(Domain.global(), cred) + println "Credential 등록 완료" +}} else {{ + println "Store null - credentials 플러그인 확인 필요" +}} +' 2>/dev/null +""") + +# 4. 환경변수 설정 +run('글로벌 환경변수 설정', f""" +curl -sf -X POST "{JENKINS}/scriptText" -u {AUTH} \ + --data-urlencode 'script= +import jenkins.model.* +import hudson.EnvVars +def instance = Jenkins.instance +def globalProps = instance.globalNodeProperties +def envVarsNodeProperty = globalProps.getAll(hudson.slaves.EnvironmentVariablesNodeProperty.class) +if (!envVarsNodeProperty) {{ + def newProp = new hudson.slaves.EnvironmentVariablesNodeProperty() + globalProps.add(newProp) + envVarsNodeProperty = [newProp] +}} +def envVars = envVarsNodeProperty[0].getEnvVars() +envVars.put("ITSM_BASE_URL", "http://127.0.0.1:9001") +envVars.put("GITEA_URL", "http://127.0.0.1:9003") +envVars.put("SERVER_HOST", "101.79.17.164") +instance.save() +println "환경변수 설정 완료" +' 2>/dev/null +""") + +# 5. 상태 확인 +run('최종 상태', f""" +HTTP=$(curl -sf -o /dev/null -w "%{{http_code}}" {JENKINS}/api/json -u {AUTH} 2>/dev/null) +echo "Jenkins API: HTTP $HTTP" +java -jar /tmp/jenkins-cli.jar -s {JENKINS} -auth {AUTH} version 2>/dev/null +""") + +client.close() +print('\n=== Jenkins 기본 설정 완료 ===') diff --git a/scripts/setup/jenkins_fix.py b/scripts/setup/jenkins_fix.py new file mode 100644 index 00000000..fc5e748f --- /dev/null +++ b/scripts/setup/jenkins_fix.py @@ -0,0 +1,21 @@ +import paramiko, sys, time +sys.stdout.reconfigure(encoding='utf-8', errors='replace') + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=15) + +def run(label, cmd, timeout=30): + print(f'\n[{label}]') + _, o, e = client.exec_command(cmd, timeout=timeout) + out = o.read().decode('utf-8', errors='replace').strip() + if out: print(out[:400]) + return out + +# Jenkins가 400을 반환하는 이유 확인 +run('Jenkins 응답 상세', 'curl -sv http://localhost:8080/api/json 2>&1 | head -30') +run('Jenkins 설정 파일', 'cat /var/lib/jenkins/config.xml 2>/dev/null | head -20') +run('Jenkins 설치 상태', 'cat /var/lib/jenkins/jenkins.install.InstallUtil.lastExecVersion 2>/dev/null') +run('Nginx Jenkins 설정', 'cat /etc/nginx/sites-enabled/jenkins 2>/dev/null | head -20') + +client.close() diff --git a/scripts/setup/jenkins_reset.py b/scripts/setup/jenkins_reset.py new file mode 100644 index 00000000..821c2fce --- /dev/null +++ b/scripts/setup/jenkins_reset.py @@ -0,0 +1,58 @@ +import paramiko, sys, time +sys.stdout.reconfigure(encoding='utf-8', errors='replace') + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=15) + +def run(label, cmd, timeout=30): + print(f'\n[{label}]') + _, o, e = client.exec_command(cmd, timeout=timeout) + print(o.read().decode('utf-8', errors='replace').strip()[:400]) + +run('Jenkins 사용자 목록', 'ls /var/lib/jenkins/users/ 2>/dev/null') +run('admin 사용자 설정', 'cat /var/lib/jenkins/users/admin_*/config.xml 2>/dev/null | head -20') +run('Security Realm', 'grep -A5 "securityRealm" /var/lib/jenkins/config.xml 2>/dev/null | head -10') + +# Jenkins 보안을 임시 비활성화 후 비밀번호 재설정 +run('보안 임시 비활성화', """ +# config.xml에서 useSecurity를 false로 변경 +sed -i 's|true|false|' /var/lib/jenkins/config.xml +echo "보안 비활성화" +grep "useSecurity" /var/lib/jenkins/config.xml +""") + +run('Jenkins 재시작', 'systemctl restart jenkins && sleep 8 && systemctl is-active jenkins') + +# 보안 비활성화 상태에서 비밀번호 재설정 Groovy 스크립트 실행 +run('API 확인 (보안 비활성화)', """ +HTTP=$(curl -sf -o /dev/null -w "%{http_code}" http://127.0.0.1:9080/api/json 2>/dev/null) +echo "HTTP: $HTTP" +""") + +run('admin 비밀번호 재설정', """ +# Jenkins Script Console을 통해 비밀번호 재설정 +curl -sf -X POST http://127.0.0.1:9080/scriptText \ + --data-urlencode 'script= +import jenkins.model.* +import hudson.security.* +def instance = Jenkins.getInstance() +def realm = new HudsonPrivateSecurityRealm(false) +realm.createAccount("admin", "Admin@2026!") +instance.setSecurityRealm(realm) +def strategy = new FullControlOnceLoggedInAuthorizationStrategy() +strategy.setAllowAnonymousRead(false) +instance.setAuthorizationStrategy(strategy) +instance.setSecurityEnabled(true) +instance.save() +println "done" +' 2>/dev/null +""") + +run('보안 재활성화 확인', """ +grep "useSecurity" /var/lib/jenkins/config.xml +""") + +run('Jenkins 재시작', 'systemctl restart jenkins && sleep 8 && systemctl is-active jenkins') + +client.close() diff --git a/scripts/setup/jenkins_set_password.py b/scripts/setup/jenkins_set_password.py new file mode 100644 index 00000000..cda9fa53 --- /dev/null +++ b/scripts/setup/jenkins_set_password.py @@ -0,0 +1,62 @@ +import paramiko, sys, time +sys.stdout.reconfigure(encoding='utf-8', errors='replace') + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=15) + +def run(label, cmd, timeout=30): + print(f'\n[{label}]') + _, o, e = client.exec_command(cmd, timeout=timeout) + out = o.read().decode('utf-8', errors='replace').strip() + if out: print(out[:300]) + return out + +# init.groovy.d 스크립트 제거 (비밀번호 "admin"으로 재설정하는 스크립트) +run('init.groovy 제거', 'rm -f /var/lib/jenkins/init.groovy.d/00_setup.groovy && ls /var/lib/jenkins/init.groovy.d/') + +# Script Console로 비밀번호 재설정 (보안 비활성화 상태) +run('비밀번호 재설정 (보안 비활성화)', """ +curl -sf -X POST http://127.0.0.1:9080/scriptText \ + --data-urlencode 'script= +import jenkins.model.* +import hudson.security.* + +def instance = Jenkins.instance + +// HudsonPrivateSecurityRealm으로 비밀번호 재설정 +def realm = new HudsonPrivateSecurityRealm(false) +realm.createAccount("admin", "1q2w3e!Q") +instance.setSecurityRealm(realm) + +def strategy = new FullControlOnceLoggedInAuthorizationStrategy() +strategy.setAllowAnonymousRead(false) +instance.setAuthorizationStrategy(strategy) +instance.setSecurityEnabled(true) +instance.save() +println "비밀번호 재설정 완료" +' 2>/dev/null || echo "Script Console 접근 실패" +""") + +# useSecurity 다시 활성화 +run('보안 재활성화', """ +sed -i 's/false<\/useSecurity>/true<\/useSecurity>/' /var/lib/jenkins/config.xml +grep "useSecurity" /var/lib/jenkins/config.xml +""") + +run('Jenkins 재시작', 'systemctl restart jenkins && sleep 10 && systemctl is-active jenkins') +time.sleep(5) + +# 새 비밀번호로 확인 +run('새 비밀번호로 API 확인', """ +for pw in '1q2w3e!Q' 'admin' 'Admin@2026!'; do + HTTP=$(curl -sf -o /dev/null -w "%{http_code}" http://127.0.0.1:9080/api/json -u "admin:$pw" 2>/dev/null) + echo "admin/$pw → HTTP $HTTP" + if [ "$HTTP" = "200" ]; then + echo "SUCCESS! 비밀번호: $pw" + break + fi +done +""") + +client.close() diff --git a/scripts/setup/jenkins_setup2.py b/scripts/setup/jenkins_setup2.py new file mode 100644 index 00000000..c5f7864a --- /dev/null +++ b/scripts/setup/jenkins_setup2.py @@ -0,0 +1,63 @@ +import paramiko, sys, time +sys.stdout.reconfigure(encoding='utf-8', errors='replace') + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=30) + +JENKINS = 'http://127.0.0.1:9080' +ADMIN_PW = 'admin' + +def run(label, cmd, timeout=60): + print(f'\n[{label}]') + _, o, e = client.exec_command(cmd, timeout=timeout) + out = o.read().decode('utf-8', errors='replace').strip() + err = e.read().decode('utf-8', errors='replace').strip() + if out: print(out[:400]) + if err: + bad = [l for l in err.splitlines() if not any(k in l.lower() for k in ['warn','info'])] + if bad: print('ERR:', '\n'.join(bad[:2])) + return out + +# 내부 포트로 확인 +run('내부 API 확인', f""" +HTTP=$(curl -sf -o /dev/null -w "%{{http_code}}" {JENKINS}/api/json -u admin:{ADMIN_PW} 2>/dev/null) +echo "HTTP: $HTTP" +curl -sf {JENKINS}/api/json -u admin:{ADMIN_PW} 2>/dev/null | python3 -c " +import sys,json; d=json.load(sys.stdin); print('Jenkins', d.get('fullName',d.get('mode','OK'))) +" 2>/dev/null || echo "auth 실패 - 비밀번호 시도 필요" +""") + +# 초기 비밀번호로 시도 +run('초기 비밀번호로 확인', f""" +INIT=$(cat /var/lib/jenkins/secrets/initialAdminPassword 2>/dev/null) +HTTP=$(curl -sf -o /dev/null -w "%{{http_code}}" {JENKINS}/api/json -u admin:$INIT 2>/dev/null) +echo "초기비번 HTTP: $HTTP" +""") + +# 플러그인 설치 (내부 포트) +run('필수 플러그인 설치', f""" +java -jar /tmp/jenkins-cli.jar -s {JENKINS} -auth admin:{ADMIN_PW} install-plugin \ + git workflow-aggregator pipeline-stage-view credentials-binding \ + ssh-agent nodejs timestamper ansicolor http_request junit \ + 2>/dev/null && echo "플러그인 설치 완료" + +# 실패 시 초기 비밀번호로 재시도 +if [ $? -ne 0 ]; then + INIT=$(cat /var/lib/jenkins/secrets/initialAdminPassword) + java -jar /tmp/jenkins-cli.jar -s {JENKINS} -auth admin:$INIT install-plugin \ + git workflow-aggregator pipeline-stage-view credentials-binding \ + ssh-agent nodejs timestamper ansicolor http_request junit \ + && echo "초기비번으로 플러그인 설치 완료" +fi +""", timeout=120) + +run('Jenkins 재시작', f""" +java -jar /tmp/jenkins-cli.jar -s {JENKINS} -auth admin:{ADMIN_PW} restart 2>/dev/null || \ +java -jar /tmp/jenkins-cli.jar -s {JENKINS} -auth admin:$(cat /var/lib/jenkins/secrets/initialAdminPassword) restart 2>/dev/null || \ +systemctl restart jenkins +sleep 10 +systemctl is-active jenkins +""") + +client.close() diff --git a/setup_gitea2.py b/scripts/setup/setup_gitea2.py similarity index 100% rename from setup_gitea2.py rename to scripts/setup/setup_gitea2.py diff --git a/setup_gitea_repos.py b/scripts/setup/setup_gitea_repos.py similarity index 100% rename from setup_gitea_repos.py rename to scripts/setup/setup_gitea_repos.py diff --git a/scripts/setup/setup_jenkins.py b/scripts/setup/setup_jenkins.py new file mode 100644 index 00000000..e5a528a2 --- /dev/null +++ b/scripts/setup/setup_jenkins.py @@ -0,0 +1,95 @@ +"""Jenkins 초기 설정 자동화""" +import paramiko, sys, time, json +sys.stdout.reconfigure(encoding='utf-8', errors='replace') + +client = paramiko.SSHClient() +client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) +client.connect('101.79.17.164', username='root', password='1q2w3e!Q', timeout=30) + +def run(label, cmd, timeout=60): + print(f'\n[{label}]') + _, o, e = client.exec_command(cmd, timeout=timeout) + out = o.read().decode('utf-8', errors='replace').strip() + err = e.read().decode('utf-8', errors='replace').strip() + if out: print(out[:500]) + if err: + bad = [l for l in err.splitlines() if not any(k in l.lower() for k in ['warn','info','downloading'])] + if bad: print('ERR:', '\n'.join(bad[:3])) + return out + +# 1. Jenkins CLI jar 다운로드 +run('CLI jar 다운로드', """ +if [ ! -f /tmp/jenkins-cli.jar ]; then + curl -sf http://localhost:8080/jnlpJars/jenkins-cli.jar -o /tmp/jenkins-cli.jar 2>/dev/null + test -f /tmp/jenkins-cli.jar && echo "다운로드 완료" || echo "실패" +fi +ls -la /tmp/jenkins-cli.jar 2>/dev/null +""") + +# 2. Jenkins 설정 완료 여부 확인 +run('Jenkins 웹 상태', """ +HTTP=$(curl -sf -o /dev/null -w "%{http_code}" http://localhost:8080/ 2>/dev/null) +echo "HTTP 상태: $HTTP" +if [ "$HTTP" = "403" ] || [ "$HTTP" = "200" ]; then + echo "Jenkins 웹 응답 정상" +else + echo "아직 초기화 중..." +fi +""") + +# 3. Groovy 스크립트로 Jenkins 설정 (초기 설정 우회) +run('Groovy 초기 설정', """ +INIT_PW=c753461ad51f4b85901e90bff6612f84 +# Jenkins init.groovy.d로 초기 설정 +mkdir -p /var/lib/jenkins/init.groovy.d + +cat > /var/lib/jenkins/init.groovy.d/00_setup.groovy << 'GROOVY' +import jenkins.model.* +import hudson.security.* +import jenkins.install.InstallState + +def instance = Jenkins.getInstance() + +// 설정 완료 처리 (wizard 건너뛰기) +if(!instance.installState.isSetupComplete()) { + InstallState.INITIAL_SETUP_COMPLETED.initializeState() +} + +// admin 계정 설정 +def hudsonRealm = new HudsonPrivateSecurityRealm(false) +hudsonRealm.createAccount('admin', 'admin') +instance.setSecurityRealm(hudsonRealm) + +def strategy = new FullControlOnceLoggedInAuthorizationStrategy() +strategy.setAllowAnonymousRead(false) +instance.setAuthorizationStrategy(strategy) + +instance.save() +println "Jenkins setup complete" +GROOVY +echo "Groovy 스크립트 생성" +""") + +# 4. Jenkins 재시작 +run('Jenkins 재시작', 'systemctl restart jenkins && sleep 10 && systemctl is-active jenkins') + +# 5. 상태 재확인 +time.sleep(10) +run('재시작 후 API 확인', """ +for i in 1 2 3 4 5; do + HTTP=$(curl -sf -o /dev/null -w "%{http_code}" http://localhost:8080/api/json -u admin:admin 2>/dev/null) + echo "시도 $i: HTTP $HTTP" + if [ "$HTTP" = "200" ]; then break; fi + sleep 5 +done +""") + +run('플러그인 설치 (필수)', """ +java -jar /tmp/jenkins-cli.jar -s http://localhost:8080 -auth admin:admin install-plugin \ + git workflow-aggregator pipeline-stage-view credentials-binding \ + ssh-agent nodejs timestamper ansicolor \ + 2>/dev/null && echo "플러그인 설치 완료" || echo "플러그인 설치 실패 (수동 필요)" +""", timeout=120) + +client.close() +print('\n=== Jenkins 초기 설정 완료 ===') diff --git a/setup_webhooks.py b/scripts/setup/setup_webhooks.py similarity index 100% rename from setup_webhooks.py rename to scripts/setup/setup_webhooks.py diff --git a/guardia_setup.ps1 b/setup/guardia_setup.ps1 similarity index 100% rename from guardia_setup.ps1 rename to setup/guardia_setup.ps1 diff --git a/workspace/guardia-messenger/Jenkinsfile b/workspace/guardia-messenger/Jenkinsfile new file mode 100644 index 00000000..79290bd0 --- /dev/null +++ b/workspace/guardia-messenger/Jenkinsfile @@ -0,0 +1,46 @@ +pipeline { + agent any + environment { + NOTIFY = "${ITSM_BASE_URL}/api/messenger/webhook" + } + options { + buildDiscarder(logRotator(numToKeepStr: '5')) + timeout(time: 10, unit: 'MINUTES') + timestamps() + } + stages { + stage('Checkout') { steps { checkout scm } } + stage('Validate') { + steps { + sh 'node --version || true' + sh "grep -E '\"expo\"' package.json | head -1 || true" + } + } + stage('Install') { + steps { sh 'npm ci --legacy-peer-deps 2>/dev/null || npm install --legacy-peer-deps' } + } + stage('Type Check') { + when { expression { fileExists('tsconfig.json') } } + steps { sh 'npx tsc --noEmit 2>/dev/null || true' } + } + stage('EAS Build Trigger') { + when { + allOf { + branch 'main' + expression { return env.EXPO_TOKEN?.trim() } + } + } + steps { + sh ''' + npm install -g @expo/eas-cli 2>/dev/null || true + eas build --platform android --non-interactive --no-wait \ + --profile production 2>/dev/null || echo "EAS 빌드 큐 등록됨" + ''' + } + } + } + post { + success { sh "curl -sf -X POST ${NOTIFY} -H 'Content-Type:application/json' -d '{\"event\":\"build_result\",\"room\":\"ops\",\"success\":true,\"result_summary\":\"✅ guardia-messenger 검증 완료 #${BUILD_NUMBER}\"}' 2>/dev/null || true" } + failure { sh "curl -sf -X POST ${NOTIFY} -H 'Content-Type:application/json' -d '{\"event\":\"build_result\",\"room\":\"ops\",\"success\":false,\"result_summary\":\"❌ guardia-messenger 빌드 실패 #${BUILD_NUMBER}\"}' 2>/dev/null || true" } + } +} diff --git a/workspace/zioinfo-web/frontend/src/components/layout/Header.css b/workspace/zioinfo-web/frontend/src/components/layout/Header.css index 3cc3e002..d6885760 100644 --- a/workspace/zioinfo-web/frontend/src/components/layout/Header.css +++ b/workspace/zioinfo-web/frontend/src/components/layout/Header.css @@ -25,8 +25,8 @@ } /* 로고 */ -.logo { display: flex; align-items: center; gap: 10px; flex-shrink: 0; } -.logo img { height: 40px; width: auto; filter: brightness(0) invert(1); } +.logo { display: flex; align-items: center; gap: 10px; flex-shrink: 0; cursor: pointer; text-decoration: none; } +.logo img { height: 40px; width: auto; } .logo-text { color: #fff; font-size: 20px; font-weight: 700; } .logo-text strong { color: var(--accent); } diff --git a/workspace/zioinfo-web/frontend/src/components/layout/Header.jsx b/workspace/zioinfo-web/frontend/src/components/layout/Header.jsx index 6d1250a6..53f64fb7 100644 --- a/workspace/zioinfo-web/frontend/src/components/layout/Header.jsx +++ b/workspace/zioinfo-web/frontend/src/components/layout/Header.jsx @@ -60,6 +60,7 @@ export default function Header() { const [activeMenu, setActiveMenu] = useState(null); const [mobileOpen, setMobileOpen] = useState(false); const [member, setMember] = useState(null); + const closeTimer = React.useRef(null); const location = useLocation(); const navigate = useNavigate(); @@ -117,10 +118,11 @@ export default function Header() { {MENU.map(menu => (
setActiveMenu(menu.id)} - onMouseLeave={() => setActiveMenu(null)}> + onMouseEnter={() => { clearTimeout(closeTimer.current); setActiveMenu(menu.id); }} + onMouseLeave={() => { closeTimer.current = setTimeout(() => setActiveMenu(null), 200); }}> {activeMenu === menu.id && ( diff --git a/workspace/zioinfo-web/frontend/src/pages/SolutionPage.jsx b/workspace/zioinfo-web/frontend/src/pages/SolutionPage.jsx index 03874f71..c66c47e4 100644 --- a/workspace/zioinfo-web/frontend/src/pages/SolutionPage.jsx +++ b/workspace/zioinfo-web/frontend/src/pages/SolutionPage.jsx @@ -287,6 +287,7 @@ export default function SolutionPage() { } /> } /> } /> + } /> ); }