zioinfo-mail/itsm/main.py
DESKTOP-TKLFCPR\ython 97afb8d51d feat(onboarding): 설치 후 자동 실행 가이드 챗봇 구현
[온보딩 API (routers/onboarding.py)]
- 8단계 온보딩 플로우:
  0. 환영 → 1. 비밀번호변경 → 2. 대시보드 → 3. 프로젝트등록
  → 4. 서버등록 → 5. 소스코드등록 → 6. 메신저봇 → 7. 완료
- POST /api/onboarding/message: 현재화면 + 사용자질문 → Ollama 답변
- 화면별 스포트라이트 target 정의 (CSS selector)
- 사용자별 단계 상태 영속 관리

[온보딩 챗봇 UI (static/onboarding.js)]
- 우측 고정 패널 (360px, 모바일 하단 슬라이드)
- 타이핑 애니메이션 효과 + 마크다운 렌더링
- 스포트라이트: 현재 단계 UI 요소를 하이라이트
- 화면 변화 감지 (MutationObserver + click 이벤트)
- 최소화/닫기/재시작 제어
- 사용자 질문 입력 → Ollama 실시간 답변
- 온보딩 완료 후 우측하단 ? 도움말 버튼
- 액션버튼: next/navigate/external/complete/skip

[설치 자동화 연동]
- install_auto.sh: 설치 완료 후 onboarding reset API 호출
- 브라우저 열릴 때 챗봇 자동 표시

사용자 경험:
  설치 완료 → 브라우저 자동 오픈 → 챗봇 우측 등장
  → "환영합니다!" → 비밀번호변경 화면 이동 안내
  → CMDB 서버등록 스포트라이트 → Gitea 소스등록
  → 완료 후 ? 버튼으로 재시작 가능

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-30 09:43:40 +09:00

346 lines
13 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from contextlib import asynccontextmanager
from fastapi import FastAPI
from fastapi.responses import FileResponse
from fastapi.staticfiles import StaticFiles
from database import init_db
from fastapi.middleware.cors import CORSMiddleware
from routers import (
approvals, assign, audit, auth, cmdb, dashboard, kb, nlcmd, rating, tasks, work,
institutions, shell_scripts, timetable, attachments, notifications,
messenger, ssh, projects, vibe,
ssl_manager, pm, incidents, oncall, batch,
si_projects, si_wbs, si_requirements, si_issues,
si_risks, si_milestones, si_change_requests, si_tests,
agents,
analytics,
ws as ws_router,
timeline,
code_review,
anomaly,
chatbot,
kb_agent,
orchestrator,
predictive,
change,
problem,
capacity,
catalog,
ldap,
pam,
vuln_scan,
report,
metrics,
finops,
tenant_mgmt,
gateway,
license as license_router,
learning,
push as push_router,
scouter as scouter_router,
deliverables,
si_report,
compliance,
jmeter,
public_checklist,
customer_portal,
onboarding,
groupware,
siem,
topology,
portfolio,
infra_ext,
)
@asynccontextmanager
async def lifespan(app: FastAPI):
# 디렉토리 생성
from pathlib import Path
(Path(__file__).parent / "uploads" / "sr_files").mkdir(parents=True, exist_ok=True)
(Path(__file__).parent / "uploads" / "workspaces").mkdir(parents=True, exist_ok=True)
await init_db()
from database import SessionLocal
from core.seed import seed_all
async with SessionLocal() as db:
await seed_all(db)
# 라이선스 상태 확인 (시작 시) — TRIAL 키는 GUARDIA_LICENSE_KEY 없이도 동작
from routers.license import get_license_status
async with SessionLocal() as db:
lic_status = await get_license_status(db)
if lic_status.get("valid"):
edition = lic_status["edition"]
days = lic_status["days_remaining"]
cust = lic_status["customer"]
if lic_status.get("is_trial"):
print(f"[LICENSE] TRIAL 체험판 활성 (D-{days}) - {cust}")
else:
print(f"[LICENSE] {edition} 라이선스 활성 ({days}일 남음) - {cust}")
if lic_status.get("expiry_warning"):
print(f"[LICENSE] 만료 {days}일 남음 - 갱신을 준비하세요.")
elif lic_status.get("expired"):
print("[LICENSE] 라이선스가 만료되었습니다. 갱신이 필요합니다.")
else:
print("[LICENSE] 라이선스 미등록 - /license 에서 무료 체험을 시작하거나 키를 등록하세요.")
# A-1: WebSocket ↔ SSE 통합 패치
from routers.ws import _integrate_with_sse_bus
_integrate_with_sse_bus()
# 백그라운드 스케줄러 시작
from core.scheduler import start_scheduler, init_batch_jobs_from_db
start_scheduler()
await init_batch_jobs_from_db() # DB에서 활성 배치 잡 자동 등록
yield
# 스케줄러 종료
from core.scheduler import stop_scheduler
stop_scheduler()
# F-2: Redis 연결 종료
try:
from core.cache import close_redis
await close_redis()
except Exception:
pass
app = FastAPI(title="GUARDiA ITSM", version="2.0.0", lifespan=lifespan)
@app.middleware("http")
async def add_copyright_header(request, call_next):
response = await call_next(request)
response.headers["X-Powered-By"] = "GUARDiA ITSM 2.0"
response.headers["X-Copyright"] = "Copyright 2026 GUARDiA All Rights Reserved"
return response
# ── F-2: Redis 캐시 종료 훅 ──────────────────────────────────────────────────
# (lifespan의 yield 이후에 실행 — close_redis는 shutdown시 호출)
# ── F-3: Rate Limiting 미들웨어 등록 ─────────────────────────────────────────
from core.ratelimit import setup_rate_limiting
setup_rate_limiting(app)
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:8001", "http://127.0.0.1:8001"],
allow_methods=["*"],
allow_headers=["*"],
)
app.include_router(auth.router)
app.include_router(dashboard.router)
app.include_router(assign.router)
app.include_router(kb.router)
app.include_router(nlcmd.router)
app.include_router(tasks.router)
app.include_router(approvals.router)
app.include_router(cmdb.router)
app.include_router(audit.router)
app.include_router(work.router)
app.include_router(rating.router)
app.include_router(institutions.router)
app.include_router(shell_scripts.router)
app.include_router(timetable.router)
app.include_router(attachments.router)
app.include_router(notifications.router)
app.include_router(messenger.router)
app.include_router(ssh.router)
app.include_router(projects.router)
app.include_router(vibe.router)
app.include_router(ssl_manager.router)
app.include_router(pm.router)
app.include_router(incidents.router)
app.include_router(oncall.router)
app.include_router(batch.router)
# ── SI 프로젝트 관리 (분석→설계→구현→인도) ─────────────────────────────────
app.include_router(si_projects.router)
app.include_router(si_wbs.router)
app.include_router(si_requirements.router)
app.include_router(si_issues.router)
app.include_router(si_risks.router)
app.include_router(si_milestones.router)
app.include_router(si_change_requests.router)
app.include_router(si_tests.router)
# ── AI 에이전트 (Paperclip × GUARDiA, Ollama 로컬 LLM) ──────────────────────
app.include_router(agents.router)
# ── Analytics (E-2 배포 성공률 트렌드, E-3 엔지니어 워크로드) ─────────────────
app.include_router(analytics.router)
# ── A-1: WebSocket 실시간 대시보드 ───────────────────────────────────────────
app.include_router(ws_router.router)
# ── A-4: 운영 이벤트 타임라인 ────────────────────────────────────────────────
app.include_router(timeline.router)
# ── B-3: 코드 리뷰 에이전트 ──────────────────────────────────────────────────
app.include_router(code_review.router)
# ── B-1: AI 이상 탐지 ────────────────────────────────────────────────────────
app.include_router(anomaly.router)
# ── B-2: 자연어 SR 접수 챗봇 ─────────────────────────────────────────────────
app.include_router(chatbot.router)
# ── B-4: KB 자동 업데이트 에이전트 ───────────────────────────────────────────
app.include_router(kb_agent.router)
# ── B-5: 멀티 에이전트 협업 오케스트레이션 ────────────────────────────────────
app.include_router(orchestrator.router)
# ── B-6: 예측 유지보수 ────────────────────────────────────────────────────────
app.include_router(predictive.router)
# ── C-2: 변경 관리 CAB ───────────────────────────────────────────────────────
app.include_router(change.router)
# ── C-3: Problem Management ─────────────────────────────────────────────────
app.include_router(problem.router)
# ── C-4: 용량 관리 대시보드 ──────────────────────────────────────────────────
app.include_router(capacity.router)
# ── C-5: 서비스 카탈로그 ──────────────────────────────────────────────────────
app.include_router(catalog.router)
# ── D-1: LDAP/AD 연동 ────────────────────────────────────────────────────────
app.include_router(ldap.router)
# ── D-3: 특권 접근 관리 (PAM) ─────────────────────────────────────────────────
app.include_router(pam.router)
# ── D-4: 보안 취약점 자동 스캔 ───────────────────────────────────────────────
app.include_router(vuln_scan.router)
# ── E-1: 월별 리포트 자동 생성 ───────────────────────────────────────────────
app.include_router(report.router)
# ── E-4: Grafana 연동 (Prometheus 메트릭) ─────────────────────────────────
app.include_router(metrics.router)
# ── E-5: FinOps 비용 분석 ────────────────────────────────────────────────
app.include_router(finops.router)
# ── F-1: 멀티테넌트 데이터 격리 ──────────────────────────────────────────
from middleware.tenant import TenantMiddleware
app.add_middleware(TenantMiddleware)
app.include_router(tenant_mgmt.router)
# ── F-5: OpenAPI 외부 연동 게이트웨이 ────────────────────────────────────
app.include_router(gateway.router)
# ── Self-Improving Learning Loop ──────────────────────────────────────────
app.include_router(learning.router)
# ── 라이선스 관리 ──────────────────────────────────────────────────────────
app.include_router(license_router.router)
# ── G-10: PWA Push 알림 ──────────────────────────────────────────────────
app.include_router(push_router.router)
# Scouter APM
app.include_router(scouter_router.router)
# PMS — 산출물 + 보고서
app.include_router(deliverables.router)
app.include_router(si_report.router)
# 준수성 점검 (시큐어코딩/웹접근성/개인정보보호)
app.include_router(compliance.router)
# 성능 테스트 (JMeter JTL 분석 + 내장 부하 테스트)
app.include_router(jmeter.router)
# 공공기관 필수 기능 체크리스트
app.include_router(public_checklist.router)
# 추가 기능
app.include_router(customer_portal.router) # 고객 셀프서비스 포털
app.include_router(onboarding.router) # 온보딩 가이드 챗봇
app.include_router(groupware.router) # 그룹웨어 전자결재 연동
app.include_router(siem.router) # SIEM 보안 이벤트 연동
app.include_router(topology.router) # 네트워크 토폴로지 시각화
app.include_router(portfolio.router) # 포트폴리오 + 리소스 관리
app.include_router(infra_ext.router) # Zero Trust + K8s + ERP
@app.get("/topology")
async def topology_page():
return FileResponse("static/index.html")
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/")
async def index():
return FileResponse("static/index.html")
@app.get("/customer")
async def customer():
return FileResponse("static/customer.html")
@app.get("/login")
async def login_page():
return FileResponse("static/login.html")
@app.get("/change-password")
async def change_password_page():
return FileResponse("static/change-password.html")
@app.get("/agents")
async def agents_page():
return FileResponse("static/agents.html")
@app.get("/incidents")
async def incidents_page():
return FileResponse("static/incidents.html")
@app.get("/ssl")
async def ssl_page():
return FileResponse("static/ssl.html")
@app.get("/pm")
async def pm_page():
return FileResponse("static/pm.html")
@app.get("/oncall")
async def oncall_page():
return FileResponse("static/oncall.html")
@app.get("/batch")
async def batch_page():
return FileResponse("static/batch.html")
@app.get("/vibe")
async def vibe_page():
return FileResponse("static/vibe.html")
@app.get("/si")
async def si_page():
return FileResponse("static/si.html")
@app.get("/license")
async def license_page():
return FileResponse("static/license.html")