Files
site11/services/news-engine-console/backend/app/api/monitoring.py
jungwoo choi 52c857fced feat: Complete backend implementation - Users, Applications, Monitoring
Phase 1 Backend 100% 완료:

 UserService (312 lines):
- 인증 시스템 (authenticate_user, JWT 토큰 생성)
- CRUD 전체 기능 (get, create, update, delete)
- 권한 기반 필터링 (role, disabled, search)
- 비밀번호 관리 (change_password, hash 검증)
- 상태 토글 및 통계 조회

 ApplicationService (254 lines):
- OAuth2 클라이언트 관리
- Client ID/Secret 자동 생성
- Secret 재생성 기능
- 소유권 검증 (ownership check)
- 통계 조회 (grant types별)

 MonitoringService (309 lines):
- 시스템 헬스 체크 (MongoDB, pipelines)
- 시스템 메트릭 (keywords, pipelines, users, apps)
- 활동 로그 조회 (필터링, 날짜 범위)
- 데이터베이스 통계 (크기, 컬렉션, 인덱스)
- 파이프라인 성능 분석
- 에러 요약

 Users API (11 endpoints + OAuth2 로그인):
- POST /login - OAuth2 password flow
- GET /me - 현재 사용자 정보
- GET / - 사용자 목록 (admin only)
- GET /stats - 사용자 통계 (admin only)
- GET /{id} - 사용자 조회 (자신 or admin)
- POST / - 사용자 생성 (admin only)
- PUT /{id} - 사용자 수정 (권한 검증)
- DELETE /{id} - 사용자 삭제 (admin only, 자기 삭제 방지)
- POST /{id}/toggle - 상태 토글 (admin only)
- POST /change-password - 비밀번호 변경

 Applications API (7 endpoints):
- GET / - 애플리케이션 목록 (admin: 전체, user: 자신 것만)
- GET /stats - 통계 (admin only)
- GET /{id} - 조회 (소유자 or admin)
- POST / - 생성 (client_secret 1회만 표시)
- PUT /{id} - 수정 (소유자 or admin)
- DELETE /{id} - 삭제 (소유자 or admin)
- POST /{id}/regenerate-secret - Secret 재생성

 Monitoring API (8 endpoints):
- GET /health - 시스템 헬스 상태
- GET /metrics - 시스템 메트릭
- GET /logs - 활동 로그 (필터링 지원)
- GET /database/stats - DB 통계 (admin only)
- GET /database/collections - 컬렉션 통계 (admin only)
- GET /pipelines/performance - 파이프라인 성능
- GET /errors/summary - 에러 요약

주요 특징:
- 🔐 역할 기반 접근 제어 (RBAC: admin/editor/viewer)
- 🔒 OAuth2 Password Flow 인증
- 🛡️ 소유권 검증 (자신의 리소스만 수정)
- 🚫 안전 장치 (자기 삭제 방지, 자기 비활성화 방지)
- 📊 종합적인 모니터링 및 통계
- 🔑 안전한 Secret 관리 (1회만 표시)
-  완전한 에러 핸들링

Backend API 총 45개 엔드포인트 완성!
- Keywords: 8
- Pipelines: 11
- Users: 11
- Applications: 7
- Monitoring: 8

다음 단계:
- Frontend 구현 (React + TypeScript + Material-UI)
- Docker & Kubernetes 배포
- Redis 통합
- 테스트 작성

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 16:58:02 +09:00

138 lines
4.3 KiB
Python

from fastapi import APIRouter, Depends, Query
from typing import Optional
from datetime import datetime
from app.core.auth import get_current_active_user, User
from app.core.database import get_database
from app.services.monitoring_service import MonitoringService
router = APIRouter()
def get_monitoring_service(db=Depends(get_database)) -> MonitoringService:
"""Dependency to get monitoring service"""
return MonitoringService(db)
@router.get("/health")
async def get_system_health(
current_user: User = Depends(get_current_active_user),
monitoring_service: MonitoringService = Depends(get_monitoring_service)
):
"""
Get overall system health status
Includes MongoDB, pipelines, and other component health checks
"""
health = await monitoring_service.get_system_health()
return health
@router.get("/metrics")
async def get_system_metrics(
current_user: User = Depends(get_current_active_user),
monitoring_service: MonitoringService = Depends(get_monitoring_service)
):
"""
Get system-wide metrics
Includes counts and aggregations for keywords, pipelines, users, and applications
"""
metrics = await monitoring_service.get_system_metrics()
return metrics
@router.get("/logs")
async def get_activity_logs(
limit: int = Query(100, ge=1, le=1000, description="Maximum number of logs"),
level: Optional[str] = Query(None, description="Filter by log level (INFO, WARNING, ERROR)"),
start_date: Optional[datetime] = Query(None, description="Filter logs after this date"),
end_date: Optional[datetime] = Query(None, description="Filter logs before this date"),
current_user: User = Depends(get_current_active_user),
monitoring_service: MonitoringService = Depends(get_monitoring_service)
):
"""
Get activity logs
Returns logs from all pipelines with optional filtering
"""
logs = await monitoring_service.get_activity_logs(
limit=limit,
level=level,
start_date=start_date,
end_date=end_date
)
return {"logs": logs, "total": len(logs)}
@router.get("/database/stats")
async def get_database_stats(
current_user: User = Depends(get_current_active_user),
monitoring_service: MonitoringService = Depends(get_monitoring_service)
):
"""
Get MongoDB database statistics (admin only)
Includes database size, collections, indexes, etc.
"""
if current_user.role != "admin":
from fastapi import HTTPException, status
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Only admins can view database statistics"
)
stats = await monitoring_service.get_database_stats()
return stats
@router.get("/database/collections")
async def get_collection_stats(
current_user: User = Depends(get_current_active_user),
monitoring_service: MonitoringService = Depends(get_monitoring_service)
):
"""
Get statistics for all collections (admin only)
Includes document counts, sizes, and index information
"""
if current_user.role != "admin":
from fastapi import HTTPException, status
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Only admins can view collection statistics"
)
collections = await monitoring_service.get_collection_stats()
return {"collections": collections, "total": len(collections)}
@router.get("/pipelines/performance")
async def get_pipeline_performance(
hours: int = Query(24, ge=1, le=168, description="Number of hours to look back"),
current_user: User = Depends(get_current_active_user),
monitoring_service: MonitoringService = Depends(get_monitoring_service)
):
"""
Get pipeline performance metrics
Shows success rates, error counts, and activity for each pipeline
"""
performance = await monitoring_service.get_pipeline_performance(hours=hours)
return performance
@router.get("/errors/summary")
async def get_error_summary(
hours: int = Query(24, ge=1, le=168, description="Number of hours to look back"),
current_user: User = Depends(get_current_active_user),
monitoring_service: MonitoringService = Depends(get_monitoring_service)
):
"""
Get summary of recent errors
Shows error counts and recent error details
"""
summary = await monitoring_service.get_error_summary(hours=hours)
return summary