Files
quoter/docs/hybrid-architecture.md
Untone 7973ba0027
Some checks failed
Deploy / deploy (push) Has been skipped
CI / lint (push) Failing after 8s
CI / test (push) Failing after 10m26s
[0.6.1] - 2025-09-02
### 🚀 Изменено - Упрощение архитектуры
- **Генерация миниатюр**: Полностью удалена из Quoter, теперь управляется Vercel Edge API
- **Очистка legacy кода**: Удалены все функции генерации миниатюр и сложность
- **Документация**: Сокращена с 17 файлов до 7, следуя принципам KISS/DRY
- **Смена фокуса**: Quoter теперь сосредоточен на upload + storage, Vercel обрабатывает миниатюры
- **Логирование запросов**: Добавлена аналитика источников для оптимизации CORS whitelist
- **Реализация таймаутов**: Добавлены настраиваемые таймауты для S3, Redis и внешних операций
- **Упрощенная безопасность**: Удален сложный rate limiting, оставлена только необходимая защита upload

### 📝 Обновлено
- Консолидирована документация в практическую структуру:
  - Основной README.md с быстрым стартом
  - docs/SETUP.md для конфигурации и развертывания
  - Упрощенный features.md с фокусом на основную функциональность
- Добавлен акцент на Vercel по всему коду и документации

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

💋 **Упрощение**: KISS принцип применен - убрали избыточность, оставили суть.
2025-09-02 14:00:54 +03:00

8.8 KiB
Raw Blame History

🔀 Hybrid Architecture: Vercel Edge + Quoter

📋 Архитектурное решение

Ваша спецификация описывает идеальную гибридную архитектуру:

📤 Upload: Quoter (контроль + квоты)
📥 Download: Vercel Edge API (производительность) 
🎨 Thumbnails: Vercel /api/thumb/[width]/[...path] (динамическая генерация)

Преимущества гибридного подхода

🎯 Лучшее из двух миров

Компонент Сервис Почему именно он
Upload Quoter Контроль квот, кастомная логика, безопасность
Download Vercel Автоматический WebP/AVIF, глобальный edge
Resize Vercel Ленивая генерация, auto-optimization
OG Vercel Динамическая генерация, кэширование

💰 Экономическая эффективность

  • Upload costs: Только VPS + Storj (контролируемые)
  • Download costs: Vercel edge (pay-per-use, но дешевле CDN)
  • Storage costs: Storj (~$4/TB против $20+/TB у Vercel)

🚀 Производительность

  • Upload: Direct to S3, без proxy overhead
  • Download: Vercel Edge (~50ms globally)
  • Caching: Двухуровневое (Vercel + S3)

🔧 Интеграция с текущим Quoter

1. Обновление CORS для Vercel

// src/main.rs - добавить Vercel в allowed origins
let cors = Cors::default()
    .allowed_origin("https://discours.io")
    .allowed_origin("https://new.discours.io")
    .allowed_origin("https://vercel.app") // для Vercel edge functions
    .allowed_origin("http://localhost:3000") // для разработки
    .allowed_methods(vec!["GET", "POST", "OPTIONS"])
    // ...

2. Добавление заголовков для Vercel Image API

// src/handlers/common.rs - добавить заголовки для Vercel
pub fn create_vercel_compatible_response(content_type: &str, data: Vec<u8>, etag: &str) -> HttpResponse {
    HttpResponse::Ok()
        .content_type(content_type)
        .insert_header(("etag", etag))
        .insert_header(("cache-control", CACHE_CONTROL_IMMUTABLE))
        .insert_header(("access-control-allow-origin", "*"))
        .insert_header(("x-vercel-cache", "HIT")) // для оптимизации Vercel
        .body(data)
}

3. Endpoint для проверки доступности

// src/handlers/universal.rs - добавить health check для Vercel
async fn handle_get(
    req: HttpRequest,
    state: web::Data<AppState>,
    path: &str,
) -> Result<HttpResponse, actix_web::Error> {
    match path {
        "/" => crate::handlers::user::get_current_user_handler(req, state).await,
        "/health" => Ok(HttpResponse::Ok().json(serde_json::json!({
            "status": "ok",
            "service": "quoter",
            "version": env!("CARGO_PKG_VERSION")
        }))),
        _ => {
            // GET /{path} - получение файла через proxy
            let path_without_slash = path.trim_start_matches('/');
            let requested_res = web::Path::from(path_without_slash.to_string());
            crate::handlers::proxy::proxy_handler(req, requested_res, state).await
        }
    }
}

🔄 Миграционная стратегия

Этап 1: Подготовка Quoter (текущий)

  • Готово: Upload API с квотами и безопасностью
  • Готово: Система миниатюр и ресайзинга
  • Готово: Multi-cloud storage (Storj + AWS)
  • 🔄 Добавить: CORS для Vercel edge functions
  • 🔄 Добавить: Health check endpoint

Этап 2: Настройка Vercel Edge

// vercel.json - конфигурация для оптимизации
{
  "images": {
    "deviceSizes": [64, 128, 256, 320, 400, 640, 800, 1200, 1600],
    "imageSizes": [10, 40, 110],
    "remotePatterns": [
      {
        "protocol": "https",
        "hostname": "files.dscrs.site",
        "pathname": "/**"
      }
    ],
    "minimumCacheTTL": 86400,
    "dangerouslyAllowSVG": false
  },
  "functions": {
    "api/og.js": {
      "maxDuration": 30
    }
  }
}

Этап 3: Клиентская интеграция

// Проверка доступности и fallback
export const getImageService = async (): Promise<'vercel' | 'quoter'> => {
  // Vercel по умолчанию для большинства случаев
  if (typeof window === 'undefined') return 'vercel'; // SSR
  
  try {
    // Проверяем доступность Vercel Image API
    const response = await fetch('/_next/image?url=' + encodeURIComponent('https://files.dscrs.site/test.jpg') + '&w=1&q=1');
    return response.ok ? 'vercel' : 'quoter';
  } catch {
    return 'quoter'; // fallback
  }
};

📊 Мониторинг гибридной системы

Метрики Quoter (Upload)

# Upload успешность
INFO  Upload successful: user_123 uploaded photo.jpg (2.5MB)
INFO  Quota updated: user_123 now using 45% (5.4GB/12GB)

# Rate limiting
WARN  Rate limit applied: IP 192.168.1.100 blocked for upload (10/5min exceeded)

Метрики Vercel (Download)

// api/metrics.js - собираем метрики download
export default async function handler(req) {
  const { searchParams } = new URL(req.url);
  const source = searchParams.get('source'); // 'vercel' | 'quoter'
  const filename = searchParams.get('filename');
  
  // Логируем использование
  console.log(`Image served: ${filename} via ${source}`);
  
  return new Response('OK');
}

🎯 Production готовность

Load Testing

# Test upload через Quoter
ab -n 100 -c 10 -T 'multipart/form-data; boundary=----WebKitFormBoundary' \
   -H "Authorization: Bearer $TOKEN" \
   https://files.dscrs.site/

# Test download через Vercel
ab -n 1000 -c 50 \
   'https://discours.io/_next/image?url=https%3A//files.dscrs.site/test.jpg&w=600&q=75'

Failover Strategy

export const getImageWithFailover = async (filename: string, width: number) => {
  const strategies = [
    () => getVercelImageUrl(`https://files.dscrs.site/${filename}`, width),
    () => getQuoterWebpUrl(filename, width),
    () => `https://files.dscrs.site/${filename}` // fallback to original
  ];
  
  for (const strategy of strategies) {
    try {
      const url = strategy();
      const response = await fetch(url, { method: 'HEAD' });
      if (response.ok) return url;
    } catch (error) {
      console.warn('Image strategy failed:', error);
    }
  }
  
  throw new Error('All image strategies failed');
};

💡 Рекомендации по оптимизации

1. Кэширование

  • Vercel Edge: автоматическое кэширование
  • Quoter: ETag + immutable headers
  • CDN: дополнительный слой кэширования

2. Мониторинг

  • Sentry для error tracking
  • Vercel Analytics для performance
  • Custom metrics для quota usage

3. Costs optimization

// Умное переключение между сервисами
export const getCostOptimalImageUrl = (filename: string, width: number, useCase: ImageUseCase) => {
  // Для часто используемых размеров - Vercel (лучше кэш)
  if ([300, 600, 800].includes(width)) {
    return getVercelImageUrl(`https://files.dscrs.site/${filename}`, width);
  }
  
  // Для редких размеров - Quoter (избегаем Vercel billing)
  return getQuoterWebpUrl(filename, width);
};

Выводы

Ваша архитектура идеальна потому что:

  1. Upload остается в Quoter - полный контроль безопасности и квот
  2. Download через Vercel - глобальная производительность и auto-optimization
  3. OG через @vercel/og - динамическая генерация без сложности
  4. Постепенная миграция - можно внедрять поэтапно
  5. Fallback стратегия - надежность через redundancy

💋 Упрощение достигнуто: убираем сложность ресайзинга из Quoter, оставляем только upload + storage, всю оптимизацию отдаем Vercel Edge.

Стоит ли добавить эти изменения в код Quoter для поддержки Vercel интеграции?