[0.6.1] - 2025-09-02
Some checks failed
CI / lint (push) Successful in 2m11s
Deploy / deploy (push) Has been skipped
CI / test (push) Failing after 9m6s

### 🚀 Изменено - Упрощение архитектуры
- **Генерация миниатюр**: Полностью удалена из Quoter, теперь управляется Vercel Edge API
- **Очистка legacy кода**: Удалены все функции генерации миниатюр и сложность
- **Документация**: Сокращена с 17 файлов до 7, следуя принципам KISS/DRY
- **Смена фокуса**: Quoter теперь сосредоточен на upload + storage, Vercel обрабатывает миниатюры
- **Логирование запросов**: Добавлена аналитика источников для оптимизации CORS whitelist
- **Реализация таймаутов**: Добавлены настраиваемые таймауты для S3, Redis и внешних операций
- **Упрощенная безопасность**: Удален сложный rate limiting, оставлена только необходимая защита upload
- **Vercel интеграция**: Добавлена поддержка Vercel Edge API с CORS и оптимизированными заголовками
- **Redis graceful fallback**: Приложение теперь работает без Redis с предупреждениями вместо паники
- **Умная логика ответов**: Автоматическое определение Vercel запросов и оптимизированные заголовки
- **Консолидация документации**: Объединены 4 Vercel документа в один comprehensive guide

### 📝 Обновлено
- Консолидирована документация в практическую структуру:
  - Основной README.md с быстрым стартом
  - docs/SETUP.md для конфигурации и развертывания
  - Упрощенный features.md с фокусом на основную функциональность
  - docs/vercel-frontend-migration.md - единый comprehensive guide для Vercel интеграции
- Добавлен акцент на Vercel по всему коду и документации
- Обновлены URL patterns в документации: quoter.discours.io → files.dscrs.site

### 🗑️ Удалено
- Избыточные файлы документации (api-reference, deployment, development, и т.д.)
- Дублирующийся контент в нескольких документах
- Излишне детальная документация для простого файлового прокси
- 4 отдельных Vercel документа: vercel-thumbnails.md, vercel-integration.md, hybrid-architecture.md, vercel-og-integration.md

💋 **Упрощение**: KISS принцип применен - убрали избыточность, оставили суть.
This commit is contained in:
2025-09-02 14:39:54 +03:00
parent 7973ba0027
commit 7746d1f38e
21 changed files with 458 additions and 863 deletions

View File

@@ -87,7 +87,7 @@ pub fn validate_token(token: &str) -> Result<bool, Box<dyn Error>> {
/// Получает user_id из JWT токена и базовые данные пользователя с таймаутом
pub async fn get_user_by_token(
token: &str,
redis: &mut MultiplexedConnection,
mut redis: Option<&mut MultiplexedConnection>,
timeout: Duration,
) -> Result<Author, Box<dyn Error>> {
// Декодируем JWT токен для получения user_id
@@ -97,42 +97,50 @@ pub async fn get_user_by_token(
info!("Extracted user_id from JWT token: {}", user_id);
// Проверяем валидность токена через сессию в Redis (опционально) с таймаутом
let token_key = format!("session:{}:{}", user_id, token);
let session_exists: bool = tokio::time::timeout(timeout, redis.exists(&token_key))
.await
.map_err(|_| {
warn!("Redis timeout checking session existence");
// Не критичная ошибка, продолжаем с базовыми данными
})
.unwrap_or(Ok(false))
.map_err(|e| {
warn!("Failed to check session existence in Redis: {}", e);
// Не критичная ошибка, продолжаем с базовыми данными
})
.unwrap_or(false);
let session_exists = if let Some(ref mut redis) = redis {
let token_key = format!("session:{}:{}", user_id, token);
tokio::time::timeout(timeout, redis.exists(&token_key))
.await
.map_err(|_| {
warn!("Redis timeout checking session existence");
// Не критичная ошибка, продолжаем с базовыми данными
})
.unwrap_or(Ok(false))
.map_err(|e| {
warn!("Failed to check session existence in Redis: {}", e);
// Не критичная ошибка, продолжаем с базовыми данными
})
.unwrap_or(false)
} else {
warn!("⚠️ Redis not available, skipping session validation");
false
};
if session_exists {
// Обновляем last_activity если сессия существует
let current_time = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
if let Some(redis) = redis {
let current_time = std::time::SystemTime::now()
.duration_since(std::time::UNIX_EPOCH)
.unwrap()
.as_secs();
let _: () = tokio::time::timeout(
timeout,
redis.hset(&token_key, "last_activity", current_time.to_string()),
)
.await
.map_err(|_| {
warn!("Redis timeout updating last_activity");
})
.unwrap_or(Ok(()))
.map_err(|e| {
warn!("Failed to update last_activity: {}", e);
})
.unwrap_or(());
let token_key = format!("session:{}:{}", user_id, token);
let _: () = tokio::time::timeout(
timeout,
redis.hset(&token_key, "last_activity", current_time.to_string()),
)
.await
.map_err(|_| {
warn!("Redis timeout updating last_activity");
})
.unwrap_or(Ok(()))
.map_err(|e| {
warn!("Failed to update last_activity: {}", e);
})
.unwrap_or(());
}
info!("Updated last_activity for session: {}", token_key);
info!("Updated last_activity for session: {}", user_id);
} else {
info!("Session not found in Redis, proceeding with JWT-only data");
}
@@ -160,10 +168,18 @@ pub async fn get_user_by_token(
/// Сохраняет имя файла в Redis для пользователя
pub async fn user_added_file(
redis: &mut MultiplexedConnection,
redis: Option<&mut MultiplexedConnection>,
user_id: &str,
filename: &str,
) -> Result<(), actix_web::Error> {
let Some(redis) = redis else {
log::warn!(
"⚠️ Redis not available, skipping file tracking for user {}",
user_id
);
return Ok(());
};
redis
.sadd::<&str, &str, ()>(user_id, filename)
.await