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,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