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

@@ -3,6 +3,7 @@ API Key Authentication Middleware
Provides reusable dependencies for API key authentication across all endpoints.
Story 3.4: Authentification API via X-API-Key
Story 6.4: Bind user_id to structlog context when user is resolved (logs include user_id).
"""
from typing import Optional, Any, Union
@@ -69,8 +70,11 @@ async def get_user_from_api_key(
try:
from services.auth_service import get_user_by_api_key
from core.logging import bind_request_context
user = get_user_by_api_key(x_api_key)
if user is not None:
bind_request_context(user_id=str(getattr(user, "id", user)))
return user
except ValueError as e:
@@ -125,21 +129,26 @@ async def get_authenticated_user_optional(
try:
user = await get_user_from_api_key(x_api_key)
if user:
from core.logging import bind_request_context
bind_request_context(user_id=str(getattr(user, "id", user)))
return user
except APIKeyError:
# Invalid API key, fall through to JWT
pass
# Fall back to JWT
if credentials:
try:
from routes.auth_routes import get_current_user
user = await get_current_user(credentials)
if user:
from core.logging import bind_request_context
bind_request_context(user_id=str(getattr(user, "id", user)))
return user
except Exception:
pass
return None
@@ -167,20 +176,25 @@ async def get_authenticated_user(
# get_user_from_api_key will raise APIKeyError for invalid keys
user = await get_user_from_api_key(x_api_key)
if user:
from core.logging import bind_request_context
bind_request_context(user_id=str(getattr(user, "id", user)))
return user
# Should not reach here - get_user_from_api_key returns None only if no key provided
raise APIKeyError("INVALID_API_KEY", "Clé API invalide ou non reconnue.")
# Fall back to JWT
if credentials:
try:
from routes.auth_routes import get_current_user
user = await get_current_user(credentials)
if user:
from core.logging import bind_request_context
bind_request_context(user_id=str(getattr(user, "id", user)))
return user
except Exception:
pass
return None
@@ -198,10 +212,12 @@ async def require_authenticated_user(
User object (guaranteed to be authenticated)
"""
user = await get_authenticated_user(credentials, x_api_key)
if not user:
raise APIKeyError("MISSING_API_KEY", "Authentification requise. Utilisez X-API-Key ou Authorization: Bearer.")
from core.logging import bind_request_context
bind_request_context(user_id=str(getattr(user, "id", user)))
return user