feat: production deployment - full update with providers, admin, glossaries, pricing, tests

Major changes across backend, frontend, infrastructure:
- Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud)
- Admin panel: user management, pricing, settings
- Glossary system with CSV import/export
- Subscription and tier quota management
- Security hardening (rate limiting, API key auth, path traversal fixes)
- Docker compose for dev, prod, and IONOS deployment
- Alembic migrations for new tables
- Frontend: dashboard, pricing page, landing page, i18n (en/fr)
- Test suite and verification scripts

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Sepehr Ramezani
2026-04-25 15:01:47 +02:00
parent 2ba4fedfc8
commit 26bd096a06
1178 changed files with 136435 additions and 3047 deletions

View File

@@ -28,7 +28,7 @@ try:
except ImportError:
PASSLIB_AVAILABLE = False
from database.connection import get_db_session
from database.connection import get_sync_session
from database.repositories import UserRepository
from database.models import User, PlanType, SubscriptionStatus
from models.subscription import PLANS
@@ -113,9 +113,38 @@ def verify_token(token: str) -> Optional[Dict[str, Any]]:
return None
def get_or_create_google_user(
email: str, name: str, avatar_url: Optional[str] = None
) -> User:
"""Find existing user by email or create one for Google OAuth."""
with get_sync_session() as db:
repo = UserRepository(db)
user = repo.get_by_email(email)
if user:
updates: Dict[str, Any] = {"last_login_at": datetime.now(timezone.utc)}
if avatar_url and not user.avatar_url:
updates["avatar_url"] = avatar_url
if not user.email_verified:
updates["email_verified"] = True
updated = repo.update(user.id, **updates)
return updated if updated else user
random_password = secrets.token_urlsafe(32)
hashed = hash_password(random_password)
user = repo.create(
email=email,
name=name,
hashed_password=hashed,
tier="free",
)
updated = repo.update(user.id, email_verified=True, avatar_url=avatar_url)
return updated if updated else user
def create_user(email: str, name: str, password: str) -> User:
"""Create a new user in the database"""
with get_db_session() as db:
with get_sync_session() as db:
repo = UserRepository(db)
# Check if email already exists
@@ -135,7 +164,7 @@ def create_user(email: str, name: str, password: str) -> User:
def authenticate_user(email: str, password: str) -> Optional[User]:
"""Authenticate user and return user object if valid"""
with get_db_session() as db:
with get_sync_session() as db:
repo = UserRepository(db)
user = repo.get_by_email(email)
@@ -152,28 +181,28 @@ def authenticate_user(email: str, password: str) -> Optional[User]:
def get_user_by_id(user_id: str) -> Optional[User]:
"""Get user by ID from database"""
with get_db_session() as db:
with get_sync_session() as db:
repo = UserRepository(db)
return repo.get_by_id(user_id)
def get_user_by_email(email: str) -> Optional[User]:
"""Get user by email from database"""
with get_db_session() as db:
with get_sync_session() as db:
repo = UserRepository(db)
return repo.get_by_email(email)
def update_user(user_id: str, updates: Dict[str, Any]) -> Optional[User]:
"""Update user fields in database"""
with get_db_session() as db:
with get_sync_session() as db:
repo = UserRepository(db)
return repo.update(user_id, **updates)
def add_credits(user_id: str, credits: int) -> bool:
"""Add credits to user account"""
with get_db_session() as db:
with get_sync_session() as db:
repo = UserRepository(db)
result = repo.add_credits(user_id, credits)
return result is not None
@@ -181,7 +210,7 @@ def add_credits(user_id: str, credits: int) -> bool:
def use_credits(user_id: str, credits: int) -> bool:
"""Use credits from user account"""
with get_db_session() as db:
with get_sync_session() as db:
repo = UserRepository(db)
return repo.use_credits(user_id, credits)
@@ -190,7 +219,7 @@ def increment_usage(
user_id: str, docs: int = 0, pages: int = 0, api_calls: int = 0
) -> bool:
"""Increment user usage counters"""
with get_db_session() as db:
with get_sync_session() as db:
repo = UserRepository(db)
result = repo.increment_usage(
user_id, docs=docs, pages=pages, api_calls=api_calls
@@ -200,7 +229,7 @@ def increment_usage(
def check_usage_limits(user_id: str) -> Dict[str, Any]:
"""Check if user is within their plan limits"""
with get_db_session() as db:
with get_sync_session() as db:
repo = UserRepository(db)
user = repo.get_by_id(user_id)
@@ -232,7 +261,7 @@ def check_usage_limits(user_id: str) -> Dict[str, Any]:
def get_user_usage_stats(user_id: str) -> Dict[str, Any]:
"""Get detailed usage statistics for a user"""
with get_db_session() as db:
with get_sync_session() as db:
repo = UserRepository(db)
user = repo.get_by_id(user_id)