feat: Initialize News Engine Console project

Create comprehensive news pipeline management and monitoring system
with backend API structure and detailed implementation roadmap.

Core Features (7):
1. Keyword Management - Pipeline keyword CRUD and control
2. Pipeline Monitoring - Processing stats and utilization metrics
3. Pipeline Control - Step-wise start/stop and scheduling
4. Logging System - Pipeline status logs and error tracking
5. User Management - User CRUD with role-based access (Admin/Editor/Viewer)
6. Application Management - OAuth2/JWT-based Application CRUD
7. System Monitoring - Service health checks and resource monitoring

Technology Stack:
- Backend: FastAPI + Motor (MongoDB async) + Redis
- Frontend: React 18 + TypeScript + Material-UI v7 (planned)
- Auth: JWT + OAuth2
- Infrastructure: Docker + Kubernetes

Project Structure:
- backend/app/api/ - 5 API routers (keywords, pipelines, users, applications, monitoring)
- backend/app/core/ - Core configurations (config, database, auth)
- backend/app/models/ - Data models (planned)
- backend/app/services/ - Business logic (planned)
- backend/app/schemas/ - Pydantic schemas (planned)
- frontend/ - React application (planned)
- k8s/ - Kubernetes manifests (planned)

Documentation:
- README.md - Project overview, current status, API endpoints, DB schema
- TODO.md - Detailed implementation plan for next sessions

Current Status:
 Project structure initialized
 Backend basic configuration (config, database, auth)
 API router skeletons (5 routers)
 Requirements and environment setup
🚧 Models, services, and schemas pending
📋 Frontend implementation pending
📋 Docker and Kubernetes deployment pending

Next Steps (See TODO.md):
1. MongoDB schema and indexes
2. Pydantic schemas with validation
3. Service layer implementation
4. Redis integration
5. Login/authentication API
6. Frontend basic setup

This provides a solid foundation for building a comprehensive
news pipeline management console system.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
jungwoo choi
2025-11-04 16:16:09 +09:00
parent e40f50005d
commit 7649844023
15 changed files with 1089 additions and 0 deletions

View File

@ -0,0 +1,289 @@
# News Engine Console
뉴스 파이프라인 관리 및 모니터링 통합 콘솔 시스템
## 프로젝트 개요
News Engine Console은 뉴스 파이프라인의 전체 lifecycle을 관리하고 모니터링하는 통합 관리 시스템입니다.
### 핵심 기능
1. **키워드 관리** - 파이프라인 키워드 CRUD, 활성화/비활성화
2. **파이프라인 모니터링** - 파이프라인별 처리 수량, 활용도 통계
3. **파이프라인 제어** - 스텝별 시작/중지, 스케줄링
4. **로깅 시스템** - 파이프라인 상태 로그, 에러 추적
5. **사용자 관리** - User CRUD, 역할 기반 권한 (Admin/Editor/Viewer)
6. **애플리케이션 관리** - OAuth2/JWT 기반 Application CRUD
7. **시스템 모니터링** - 서비스 헬스체크, 리소스 사용량
## 기술 스택
### Backend
- FastAPI (Python 3.11)
- Motor (MongoDB async driver)
- Redis (캐싱, Pub/Sub)
- JWT + OAuth2 인증
### Frontend (예정)
- React 18 + TypeScript
- Material-UI v7
- React Query
- Recharts (통계 차트)
### Infrastructure
- Docker
- Kubernetes
- MongoDB (ai_writer_db)
- Redis
## 프로젝트 구조
```
services/news-engine-console/
├── README.md
├── TODO.md # 상세 구현 계획
├── backend/
│ ├── Dockerfile
│ ├── requirements.txt
│ ├── main.py
│ ├── .env.example
│ └── app/
│ ├── api/ # API 엔드포인트
│ │ ├── keywords.py # ✅ 키워드 관리
│ │ ├── pipelines.py # ✅ 파이프라인 제어/모니터링
│ │ ├── users.py # ✅ 사용자 관리
│ │ ├── applications.py # ✅ Application 관리
│ │ └── monitoring.py # ✅ 시스템 모니터링
│ ├── core/ # 핵심 설정
│ │ ├── config.py # ✅ 설정 관리
│ │ ├── database.py # ✅ MongoDB 연결
│ │ └── auth.py # ✅ JWT/OAuth2 인증
│ ├── models/ # 데이터 모델 (TODO)
│ ├── services/ # 비즈니스 로직 (TODO)
│ └── schemas/ # Pydantic 스키마 (TODO)
├── frontend/ # TODO
│ └── src/
│ ├── api/
│ ├── components/
│ ├── pages/
│ └── types/
└── k8s/ # TODO
├── namespace.yaml
├── backend-deployment.yaml
├── frontend-deployment.yaml
└── service.yaml
```
## 현재 구현 상태
### ✅ 완료
- [x] 프로젝트 디렉토리 구조
- [x] Backend 기본 설정 (config, database, auth)
- [x] API 라우터 기본 구조 (5개 라우터)
- Keywords API
- Pipelines API
- Users API
- Applications API
- Monitoring API
### 🚧 진행 중
- [ ] Backend 상세 구현 (models, services, schemas)
- [ ] MongoDB 컬렉션 및 인덱스 설계
- [ ] Redis 연결 및 캐싱 로직
### 📋 예정
- [ ] Frontend 구현
- [ ] Dockerfile 작성
- [ ] Kubernetes 배포 설정
- [ ] CI/CD 파이프라인
- [ ] API 문서 (OpenAPI/Swagger)
## API 엔드포인트
### Keywords API (`/api/v1/keywords`)
- `GET /` - 키워드 목록 조회
- `POST /` - 키워드 생성
- `PUT /{keyword_id}` - 키워드 수정
- `DELETE /{keyword_id}` - 키워드 삭제
### Pipelines API (`/api/v1/pipelines`)
- `GET /` - 파이프라인 목록 및 상태
- `GET /{pipeline_id}/stats` - 파이프라인 통계
- `POST /{pipeline_id}/start` - 파이프라인 시작
- `POST /{pipeline_id}/stop` - 파이프라인 중지
### Users API (`/api/v1/users`)
- `GET /` - 사용자 목록
- `POST /` - 사용자 생성
- `GET /me` - 현재 사용자 정보
### Applications API (`/api/v1/applications`)
- `GET /` - Application 목록
- `POST /` - Application 생성 (OAuth2 클라이언트 등록)
### Monitoring API (`/api/v1/monitoring`)
- `GET /system` - 시스템 상태
- `GET /logs` - 파이프라인 로그
## 로컬 개발 환경 설정
### Prerequisites
- Python 3.11+
- MongoDB (localhost:27017)
- Redis (localhost:6379)
### Backend 실행
```bash
cd services/news-engine-console/backend
# 가상환경 생성 (선택)
python3 -m venv venv
source venv/bin/activate
# 의존성 설치
pip install -r requirements.txt
# 환경 변수 설정
cp .env.example .env
# .env 파일 수정
# 서버 실행
python main.py
```
서버 실행 후: http://localhost:8100/docs (Swagger UI)
## 환경 변수
```env
# MongoDB
MONGODB_URL=mongodb://localhost:27017
DB_NAME=ai_writer_db
# Redis
REDIS_URL=redis://localhost:6379
# JWT
SECRET_KEY=your-secret-key-here
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
# Service
SERVICE_NAME=news-engine-console
API_V1_STR=/api/v1
PORT=8100
# CORS
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3100
```
## 다음 단계 (TODO.md 참조)
### Phase 1: Backend 완성 (우선순위 높음)
1. MongoDB 스키마 설계
- keywords 컬렉션
- pipelines 컬렉션
- users 컬렉션
- applications 컬렉션
- logs 컬렉션
2. Pydantic 모델 및 스키마 작성
- Request/Response 모델
- 유효성 검증
3. 비즈니스 로직 구현
- KeywordService
- PipelineService
- UserService
- ApplicationService
- MonitoringService
4. Redis 통합
- 캐싱 레이어
- Pub/Sub for real-time updates
### Phase 2: Frontend 구현
1. React 프로젝트 설정
2. Material-UI 레이아웃
3. 페이지 구현
- Dashboard (통계 요약)
- Keywords Management
- Pipelines Control
- Users Management
- Applications Management
- System Monitoring
### Phase 3: 배포
1. Dockerfile 작성
2. Kubernetes 매니페스트
3. CI/CD 설정
## 데이터베이스 설계 (Draft)
### keywords 컬렉션
```json
{
"_id": "ObjectId",
"keyword": "string",
"category": "string",
"status": "active|inactive",
"created_at": "datetime",
"updated_at": "datetime",
"created_by": "user_id"
}
```
### pipelines 컬렉션
```json
{
"_id": "ObjectId",
"name": "string",
"type": "rss|translation|image",
"status": "running|stopped|error",
"config": {},
"stats": {
"total_processed": 0,
"success_count": 0,
"error_count": 0,
"last_run": "datetime"
}
}
```
### users 컬렉션
```json
{
"_id": "ObjectId",
"username": "string",
"email": "string",
"hashed_password": "string",
"full_name": "string",
"role": "admin|editor|viewer",
"disabled": false,
"created_at": "datetime"
}
```
## 역할 기반 권한
- **Admin**: 모든 기능 접근
- **Editor**: 키워드/파이프라인 관리, 모니터링 조회
- **Viewer**: 조회만 가능
## 기여 가이드
1. 기능 구현 전 TODO.md 확인
2. API 엔드포인트 추가 시 문서 업데이트
3. 테스트 코드 작성
4. Commit 메시지 규칙 준수
## 라이선스
Part of Site11 Platform - Internal Use
---
**최종 업데이트**: 2024-01-15
**버전**: 0.1.0 (Alpha)
**작성자**: Site11 Development Team

View File

@ -0,0 +1,475 @@
# News Engine Console - 구현 계획
다음 세션을 위한 상세 구현 계획
---
## 🎯 Phase 1: Backend 완성 (우선순위)
### 1.1 데이터 모델 구현
**models/keyword.py**
```python
class Keyword:
_id: ObjectId
keyword: str
category: str # 'people', 'topics', 'companies'
status: str # 'active', 'inactive'
pipeline_type: str # 'rss', 'translation', 'all'
priority: int # 1-10
metadata: dict
created_at: datetime
updated_at: datetime
created_by: str
```
**models/pipeline.py**
```python
class Pipeline:
_id: ObjectId
name: str
type: str # 'rss_collector', 'translator', 'image_generator'
status: str # 'running', 'stopped', 'error'
config: dict
schedule: str # cron expression
stats: PipelineStats
last_run: datetime
next_run: datetime
```
**models/user.py**
```python
class User:
_id: ObjectId
username: str (unique)
email: str (unique)
hashed_password: str
full_name: str
role: str # 'admin', 'editor', 'viewer'
disabled: bool
created_at: datetime
last_login: datetime
```
**models/application.py**
```python
class Application:
_id: ObjectId
name: str
client_id: str (unique)
client_secret: str (hashed)
redirect_uris: List[str]
grant_types: List[str]
scopes: List[str]
owner_id: str
created_at: datetime
```
### 1.2 Pydantic 스키마 작성
**schemas/keyword.py**
- KeywordCreate
- KeywordUpdate
- KeywordResponse
- KeywordList
**schemas/pipeline.py**
- PipelineCreate
- PipelineUpdate
- PipelineResponse
- PipelineStats
- PipelineList
**schemas/user.py**
- UserCreate
- UserUpdate
- UserResponse
- UserLogin
**schemas/application.py**
- ApplicationCreate
- ApplicationUpdate
- ApplicationResponse
### 1.3 서비스 레이어 구현
**services/keyword_service.py**
- `async def get_keywords(filters, pagination)`
- `async def create_keyword(keyword_data)`
- `async def update_keyword(keyword_id, update_data)`
- `async def delete_keyword(keyword_id)`
- `async def toggle_keyword_status(keyword_id)`
- `async def get_keyword_stats(keyword_id)`
**services/pipeline_service.py**
- `async def get_pipelines()`
- `async def get_pipeline_stats(pipeline_id)`
- `async def start_pipeline(pipeline_id)`
- `async def stop_pipeline(pipeline_id)`
- `async def restart_pipeline(pipeline_id)`
- `async def get_pipeline_logs(pipeline_id, limit)`
- `async def update_pipeline_config(pipeline_id, config)`
**services/user_service.py**
- `async def create_user(user_data)`
- `async def authenticate_user(username, password)`
- `async def get_user_by_username(username)`
- `async def update_user(user_id, update_data)`
- `async def delete_user(user_id)`
**services/application_service.py**
- `async def create_application(app_data)`
- `async def get_applications(user_id)`
- `async def regenerate_client_secret(app_id)`
- `async def delete_application(app_id)`
**services/monitoring_service.py**
- `async def get_system_health()`
- `async def get_service_status()`
- `async def get_database_stats()`
- `async def get_redis_stats()`
- `async def get_recent_logs(limit)`
### 1.4 Redis 통합
**core/redis_client.py**
```python
class RedisClient:
async def get(key)
async def set(key, value, expire)
async def delete(key)
async def publish(channel, message)
async def subscribe(channel, callback)
```
**사용 케이스**:
- 파이프라인 상태 캐싱
- 실시간 통계 업데이트 (Pub/Sub)
- 사용자 세션 관리
- Rate limiting
### 1.5 API 엔드포인트 완성
**keywords.py**
- [x] GET / - 목록 조회 (기본 구조)
- [ ] 필터링 (category, status, search)
- [ ] 페이지네이션
- [ ] 정렬 (created_at, priority)
- [ ] GET /{id}/stats - 키워드 통계
- [ ] POST /{id}/toggle - 활성화/비활성화
**pipelines.py**
- [x] GET / - 목록 조회 (기본 구조)
- [ ] GET /{id}/logs - 로그 조회
- [ ] POST /{id}/restart - 재시작
- [ ] PUT /{id}/config - 설정 업데이트
- [ ] GET /types - 파이프라인 타입 목록
**users.py**
- [x] GET / - 목록 조회 (기본 구조)
- [ ] PUT /{id} - 사용자 수정
- [ ] DELETE /{id} - 사용자 삭제
- [ ] POST /login - 로그인 (JWT 발급)
- [ ] POST /register - 회원가입
**applications.py**
- [x] GET / - 목록 조회 (기본 구조)
- [ ] GET /{id} - 상세 조회
- [ ] PUT /{id} - 수정
- [ ] DELETE /{id} - 삭제
- [ ] POST /{id}/regenerate-secret - 시크릿 재생성
**monitoring.py**
- [x] GET /system - 시스템 상태 (기본 구조)
- [ ] GET /services - 서비스별 상태
- [ ] GET /database - DB 통계
- [ ] GET /redis - Redis 상태
- [ ] GET /pipelines/activity - 파이프라인 활동 로그
---
## 🎨 Phase 2: Frontend 구현
### 2.1 프로젝트 설정
```bash
cd frontend
npm create vite@latest . -- --template react-ts
npm install @mui/material @emotion/react @emotion/styled
npm install @tanstack/react-query axios react-router-dom
npm install recharts date-fns
```
### 2.2 레이아웃 구현
**components/Layout/AppLayout.tsx**
- Sidebar with navigation
- Top bar with user info
- Main content area
**components/Layout/Sidebar.tsx**
- Dashboard
- Keywords
- Pipelines
- Users
- Applications
- Monitoring
### 2.3 페이지 구현
**pages/Dashboard.tsx**
- 전체 통계 요약
- 파이프라인 상태 차트
- 최근 활동 로그
- 키워드 활용도 TOP 10
**pages/Keywords.tsx**
- 키워드 목록 테이블
- 검색, 필터, 정렬
- 추가/수정/삭제 모달
- 활성화/비활성화 토글
- 키워드별 통계 차트
**pages/Pipelines.tsx**
- 파이프라인 카드 그리드
- 상태별 필터 (Running, Stopped, Error)
- 시작/중지 버튼
- 실시간 로그 스트림
- 통계 차트
**pages/Users.tsx**
- 사용자 목록 테이블
- 역할 필터 (Admin, Editor, Viewer)
- 추가/수정/삭제 모달
- 마지막 로그인 시간
**pages/Applications.tsx**
- Application 카드 그리드
- Client ID/Secret 표시
- 생성/수정/삭제
- Secret 재생성 기능
**pages/Monitoring.tsx**
- 시스템 헬스체크 대시보드
- 서비스별 상태 (MongoDB, Redis, etc.)
- CPU/메모리 사용량 차트
- 실시간 로그 스트림
### 2.4 API 클라이언트
**api/client.ts**
```typescript
import axios from 'axios';
const apiClient = axios.create({
baseURL: import.meta.env.VITE_API_URL || 'http://localhost:8100/api/v1',
headers: {
'Content-Type': 'application/json'
}
});
// Interceptors for auth token
apiClient.interceptors.request.use(config => {
const token = localStorage.getItem('access_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
return config;
});
export default apiClient;
```
### 2.5 TypeScript 타입 정의
**types/index.ts**
- Keyword
- Pipeline
- User
- Application
- PipelineStats
- SystemStatus
---
## 🐳 Phase 3: Docker & Kubernetes
### 3.1 Backend Dockerfile
```dockerfile
FROM python:3.11-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8100
CMD ["python", "main.py"]
```
### 3.2 Frontend Dockerfile
```dockerfile
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json ./
RUN npm install
COPY . .
RUN npm run build
FROM nginx:alpine
COPY --from=builder /app/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
```
### 3.3 Kubernetes 매니페스트
**k8s/namespace.yaml**
```yaml
apiVersion: v1
kind: Namespace
metadata:
name: site11-console
```
**k8s/backend-deployment.yaml**
- Deployment with 2 replicas
- ConfigMap for env vars
- Secret for sensitive data
- Service (ClusterIP)
**k8s/frontend-deployment.yaml**
- Deployment with 2 replicas
- Service (LoadBalancer or Ingress)
---
## 📊 Phase 4: 고급 기능
### 4.1 실시간 업데이트
- WebSocket 연결 (파이프라인 상태)
- Server-Sent Events (로그 스트림)
- Redis Pub/Sub 활용
### 4.2 알림 시스템
- 파이프라인 에러 시 알림
- 키워드 처리 완료 알림
- 이메일/Slack 통합
### 4.3 스케줄링
- Cron 기반 파이프라인 스케줄
- 수동 실행 vs 자동 실행
- 스케줄 히스토리
### 4.4 통계 & 분석
- 일/주/월별 처리 통계
- 키워드별 성과 분석
- 파이프라인 성능 메트릭
- CSV 다운로드
---
## 🧪 Phase 5: 테스트 & 문서화
### 5.1 Backend 테스트
- pytest fixtures
- API endpoint tests
- Integration tests
- Coverage report
### 5.2 Frontend 테스트
- React Testing Library
- Component tests
- E2E tests (Playwright)
### 5.3 API 문서
- OpenAPI/Swagger 자동 생성
- API 예시 코드
- 에러 응답 명세
---
## 🚀 우선순위
### 즉시 시작 (다음 세션)
1. **MongoDB 스키마 및 인덱스 생성**
- keywords, pipelines, users 컬렉션
- 인덱스 설계
2. **Pydantic 스키마 작성**
- Request/Response 모델
- 유효성 검증
3. **키워드 관리 기능 완성**
- KeywordService 구현
- CRUD API 완성
- 단위 테스트
4. **로그인 API 구현**
- JWT 토큰 발급
- User 인증
### 중기 목표 (1-2주)
1. 파이프라인 제어 API 완성
2. Frontend 기본 구조
3. Dashboard 페이지
4. Dockerfile 작성
### 장기 목표 (1개월)
1. Frontend 전체 페이지
2. Kubernetes 배포
3. 실시간 모니터링
4. 알림 시스템
---
## 📝 체크리스트
### Backend
- [x] 프로젝트 구조
- [x] 기본 설정 (config, database, auth)
- [x] API 라우터 기본 구조
- [ ] Pydantic 스키마
- [ ] MongoDB 컬렉션 및 인덱스
- [ ] 서비스 레이어 구현
- [ ] Redis 통합
- [ ] 로그인/인증 API
- [ ] 에러 핸들링
- [ ] 로깅 시스템
### Frontend
- [ ] 프로젝트 설정
- [ ] 레이아웃 및 라우팅
- [ ] 로그인 페이지
- [ ] Dashboard
- [ ] Keywords 페이지
- [ ] Pipelines 페이지
- [ ] Users 페이지
- [ ] Applications 페이지
- [ ] Monitoring 페이지
### DevOps
- [ ] Backend Dockerfile
- [ ] Frontend Dockerfile
- [ ] docker-compose.yml
- [ ] Kubernetes 매니페스트
- [ ] CI/CD 설정
---
**다음 세션 시작 시**: 이 TODO.md를 확인하고 체크리스트 업데이트

View File

@ -0,0 +1,19 @@
# MongoDB
MONGODB_URL=mongodb://localhost:27017
DB_NAME=ai_writer_db
# Redis
REDIS_URL=redis://localhost:6379
# JWT
SECRET_KEY=your-secret-key-here-change-in-production
ALGORITHM=HS256
ACCESS_TOKEN_EXPIRE_MINUTES=30
# Service
SERVICE_NAME=news-engine-console
API_V1_STR=/api/v1
PORT=8100
# CORS
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:3100

View File

@ -0,0 +1 @@
# News Engine Console Backend

View File

@ -0,0 +1 @@
# API Routers

View File

@ -0,0 +1,14 @@
from fastapi import APIRouter, Depends
from app.core.auth import get_current_active_user, User
router = APIRouter()
@router.get("/")
async def get_applications(current_user: User = Depends(get_current_active_user)):
"""Get all OAuth2 applications"""
return {"applications": [], "total": 0}
@router.post("/")
async def create_application(app_data: dict, current_user: User = Depends(get_current_active_user)):
"""Create new OAuth2 application"""
return {"message": "Application created"}

View File

@ -0,0 +1,39 @@
from fastapi import APIRouter, Depends, HTTPException
from typing import List
from app.core.auth import get_current_active_user, User
router = APIRouter()
@router.get("/")
async def get_keywords(current_user: User = Depends(get_current_active_user)):
"""Get all keywords"""
# TODO: Implement keyword retrieval from MongoDB
return {"keywords": [], "total": 0}
@router.post("/")
async def create_keyword(
keyword_data: dict,
current_user: User = Depends(get_current_active_user)
):
"""Create new keyword"""
# TODO: Implement keyword creation
return {"message": "Keyword created", "keyword": keyword_data}
@router.put("/{keyword_id}")
async def update_keyword(
keyword_id: str,
keyword_data: dict,
current_user: User = Depends(get_current_active_user)
):
"""Update keyword"""
# TODO: Implement keyword update
return {"message": "Keyword updated", "keyword_id": keyword_id}
@router.delete("/{keyword_id}")
async def delete_keyword(
keyword_id: str,
current_user: User = Depends(get_current_active_user)
):
"""Delete keyword"""
# TODO: Implement keyword deletion
return {"message": "Keyword deleted", "keyword_id": keyword_id}

View File

@ -0,0 +1,14 @@
from fastapi import APIRouter, Depends
from app.core.auth import get_current_active_user, User
router = APIRouter()
@router.get("/system")
async def get_system_status(current_user: User = Depends(get_current_active_user)):
"""Get system status"""
return {"status": "healthy", "services": []}
@router.get("/logs")
async def get_logs(current_user: User = Depends(get_current_active_user)):
"""Get pipeline logs"""
return {"logs": []}

View File

@ -0,0 +1,24 @@
from fastapi import APIRouter, Depends
from app.core.auth import get_current_active_user, User
router = APIRouter()
@router.get("/")
async def get_pipelines(current_user: User = Depends(get_current_active_user)):
"""Get all pipelines and their status"""
return {"pipelines": [], "total": 0}
@router.get("/{pipeline_id}/stats")
async def get_pipeline_stats(pipeline_id: str, current_user: User = Depends(get_current_active_user)):
"""Get pipeline statistics"""
return {"pipeline_id": pipeline_id, "stats": {}}
@router.post("/{pipeline_id}/start")
async def start_pipeline(pipeline_id: str, current_user: User = Depends(get_current_active_user)):
"""Start pipeline"""
return {"message": "Pipeline started", "pipeline_id": pipeline_id}
@router.post("/{pipeline_id}/stop")
async def stop_pipeline(pipeline_id: str, current_user: User = Depends(get_current_active_user)):
"""Stop pipeline"""
return {"message": "Pipeline stopped", "pipeline_id": pipeline_id}

View File

@ -0,0 +1,19 @@
from fastapi import APIRouter, Depends
from app.core.auth import get_current_active_user, User
router = APIRouter()
@router.get("/")
async def get_users(current_user: User = Depends(get_current_active_user)):
"""Get all users"""
return {"users": [], "total": 0}
@router.post("/")
async def create_user(user_data: dict, current_user: User = Depends(get_current_active_user)):
"""Create new user"""
return {"message": "User created"}
@router.get("/me")
async def get_current_user_info(current_user: User = Depends(get_current_active_user)):
"""Get current user info"""
return current_user

View File

@ -0,0 +1,75 @@
from datetime import datetime, timedelta
from typing import Optional
from jose import JWTError, jwt
from passlib.context import CryptContext
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel
from app.core.config import settings
# Password hashing
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
oauth2_scheme = OAuth2PasswordBearer(tokenUrl=f"{settings.API_V1_STR}/auth/login")
# Models
class Token(BaseModel):
access_token: str
token_type: str
class TokenData(BaseModel):
username: Optional[str] = None
class User(BaseModel):
username: str
email: Optional[str] = None
full_name: Optional[str] = None
disabled: Optional[bool] = None
role: str = "viewer" # admin, editor, viewer
class UserInDB(User):
hashed_password: str
# Password functions
def verify_password(plain_password: str, hashed_password: str) -> bool:
return pwd_context.verify(plain_password, hashed_password)
def get_password_hash(password: str) -> str:
return pwd_context.hash(password)
# JWT functions
def create_access_token(data: dict, expires_delta: Optional[timedelta] = None):
to_encode = data.copy()
if expires_delta:
expire = datetime.utcnow() + expires_delta
else:
expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
encoded_jwt = jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
return encoded_jwt
async def get_current_user(token: str = Depends(oauth2_scheme)):
credentials_exception = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Could not validate credentials",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, settings.SECRET_KEY, algorithms=[settings.ALGORITHM])
username: str = payload.get("sub")
if username is None:
raise credentials_exception
token_data = TokenData(username=username)
except JWTError:
raise credentials_exception
# TODO: Get user from database
user = User(username=token_data.username, role="admin")
if user is None:
raise credentials_exception
return user
async def get_current_active_user(current_user: User = Depends(get_current_user)):
if current_user.disabled:
raise HTTPException(status_code=400, detail="Inactive user")
return current_user

View File

@ -0,0 +1,32 @@
from pydantic_settings import BaseSettings
from typing import List
class Settings(BaseSettings):
# MongoDB
MONGODB_URL: str = "mongodb://localhost:27017"
DB_NAME: str = "ai_writer_db"
# Redis
REDIS_URL: str = "redis://localhost:6379"
# JWT
SECRET_KEY: str = "dev-secret-key-change-in-production"
ALGORITHM: str = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
# Service
SERVICE_NAME: str = "news-engine-console"
API_V1_STR: str = "/api/v1"
PORT: int = 8100
# CORS
ALLOWED_ORIGINS: List[str] = [
"http://localhost:3000",
"http://localhost:3100"
]
class Config:
env_file = ".env"
case_sensitive = True
settings = Settings()

View File

@ -0,0 +1,24 @@
from motor.motor_asyncio import AsyncIOMotorClient
from app.core.config import settings
class Database:
client: AsyncIOMotorClient = None
db = None
db_instance = Database()
async def connect_to_mongo():
"""Connect to MongoDB"""
db_instance.client = AsyncIOMotorClient(settings.MONGODB_URL)
db_instance.db = db_instance.client[settings.DB_NAME]
print(f"Connected to MongoDB: {settings.DB_NAME}")
async def close_mongo_connection():
"""Close MongoDB connection"""
if db_instance.client:
db_instance.client.close()
print("Closed MongoDB connection")
def get_database():
"""Get database instance"""
return db_instance.db

View File

@ -0,0 +1,52 @@
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from contextlib import asynccontextmanager
import uvicorn
from app.core.config import settings
from app.core.database import connect_to_mongo, close_mongo_connection
from app.api import keywords, pipelines, users, applications, monitoring
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup
await connect_to_mongo()
yield
# Shutdown
await close_mongo_connection()
app = FastAPI(
title="News Engine Console API",
description="뉴스 파이프라인 관리 및 모니터링 시스템",
version="1.0.0",
lifespan=lifespan
)
# CORS
app.add_middleware(
CORSMiddleware,
allow_origins=settings.ALLOWED_ORIGINS,
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Health check
@app.get("/health")
async def health_check():
return {"status": "healthy", "service": settings.SERVICE_NAME}
# Include routers
app.include_router(keywords.router, prefix=f"{settings.API_V1_STR}/keywords", tags=["Keywords"])
app.include_router(pipelines.router, prefix=f"{settings.API_V1_STR}/pipelines", tags=["Pipelines"])
app.include_router(users.router, prefix=f"{settings.API_V1_STR}/users", tags=["Users"])
app.include_router(applications.router, prefix=f"{settings.API_V1_STR}/applications", tags=["Applications"])
app.include_router(monitoring.router, prefix=f"{settings.API_V1_STR}/monitoring", tags=["Monitoring"])
if __name__ == "__main__":
uvicorn.run(
"main:app",
host="0.0.0.0",
port=settings.PORT,
reload=True
)

View File

@ -0,0 +1,11 @@
fastapi==0.104.1
uvicorn[standard]==0.24.0
motor==3.3.2
pydantic==2.5.0
pydantic-settings==2.1.0
python-jose[cryptography]==3.3.0
passlib[bcrypt]==1.7.4
python-multipart==0.0.6
redis==5.0.1
httpx==0.25.2
python-dotenv==1.0.0