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

244 lines
8.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 🔀 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**
```rust
// 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**
```rust
// 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 для проверки доступности**
```rust
// 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
```javascript
// 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: Клиентская интеграция
```typescript
// Проверка доступности и 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)
```log
# 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)
```javascript
// 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
```bash
# 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
```typescript
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**
```typescript
// Умное переключение между сервисами
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 интеграции?