Initial commit: RSS platform phase 1 skeleton with code review fixes
Features: - FastAPI + SQLAlchemy 2.0 async + PostgreSQL/pgvector + Redis backend - Vue 3 + TypeScript + Element Plus frontend - JWT auth with access/refresh tokens and revocation - Admin/member RBAC - RSS feed CRUD and article listing - Settings management with Fernet encryption for sensitive values - Redis distributed lock service - Alembic initial migration - Docker Compose development environment Fixes from code review: - Fix DB session leak in dependency injection - Restrict registration to admin only - Add default admin password warning - Implement JWT refresh tokens and jti blacklist - Strengthen password policy - Use func.count for pagination totals - Replace NullPool with AsyncAdaptedQueuePool - Remove init_db from lifespan to enforce alembic migrations - Add request_id middleware and logging filter - Fix vite.config.ts env loading - Add frontend token refresh interceptor - Add Vue error handler Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
"""Application configuration."""
|
||||
from pathlib import Path
|
||||
|
||||
from pydantic import Field
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
"""Application settings loaded from environment variables."""
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
env_file_encoding="utf-8",
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
# Database
|
||||
DATABASE_URL: str = "postgresql+asyncpg://rss:rss@postgres:5432/rss_platform"
|
||||
|
||||
# Redis
|
||||
REDIS_URL: str = "redis://redis:6379/0"
|
||||
|
||||
# JWT
|
||||
SECRET_KEY: str = Field(..., min_length=32)
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 15
|
||||
REFRESH_TOKEN_EXPIRE_DAYS: int = 7
|
||||
|
||||
# AI
|
||||
AI_DEFAULT_PROVIDER: str = "openai"
|
||||
AI_DEFAULT_MODEL: str = "gpt-4o-mini"
|
||||
|
||||
# Storage
|
||||
STORAGE_TYPE: str = "minio"
|
||||
MINIO_ENDPOINT: str = "minio:9000"
|
||||
MINIO_ACCESS_KEY: str = "minioadmin"
|
||||
MINIO_SECRET_KEY: str = "minioadmin"
|
||||
MINIO_BUCKET: str = "rss-platform"
|
||||
|
||||
# CORS
|
||||
CORS_ALLOWED_ORIGINS: str = ""
|
||||
|
||||
# Default admin
|
||||
DEFAULT_ADMIN_USERNAME: str = "admin"
|
||||
DEFAULT_ADMIN_PASSWORD: str = "admin"
|
||||
|
||||
# Sensitive settings encryption
|
||||
SETTINGS_ENCRYPTION_KEY: str = ""
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL: str = "INFO"
|
||||
|
||||
# RSS Fetching
|
||||
FETCH_CONCURRENCY: int = 10
|
||||
FETCH_TIMEOUT: int = 30
|
||||
DEFAULT_FETCH_INTERVAL: int = 60
|
||||
MIN_FETCH_INTERVAL: int = 15
|
||||
|
||||
# Ports (for reference)
|
||||
BACKEND_PORT: int = 8000
|
||||
FRONTEND_PORT: int = 5173
|
||||
|
||||
@property
|
||||
def cors_origins(self) -> list[str]:
|
||||
"""Parse CORS_ALLOWED_ORIGINS into list."""
|
||||
if not self.CORS_ALLOWED_ORIGINS:
|
||||
return []
|
||||
return [origin.strip() for origin in self.CORS_ALLOWED_ORIGINS.split(",") if origin.strip()]
|
||||
|
||||
|
||||
settings = Settings()
|
||||
Reference in New Issue
Block a user