### New Documentation: - **URL Format Guide**: Complete guide for image resizer URL patterns - **Hybrid Architecture**: Vercel Edge + Quoter integration strategy - **Updated How-it-works**: Comprehensive system architecture with diagrams - **Enhanced Configuration**: Security settings, troubleshooting, Vercel integration ### Documentation Structure: 📋 Architecture & Principles: - 🚀 How Quoter Works (detailed system architecture) - 🔀 Hybrid Architecture (Vercel + Quoter best practices) - 📐 URL Format (complete resizer URL guide) 🛡️ Security & Configuration: - 🔒 Security & DDoS Protection (comprehensive guide) - ⚙️ Configuration (updated with new settings) - 🚀 Deployment & 📊 Monitoring 🎨 Integrations: - Vercel OG Integration guides - Edge Function examples ### Key Features Documented: - Complete URL patterns for image resizing - Security rate limiting configuration - Hybrid upload (Quoter) + download (Vercel) strategy - JWT validation and session management - Multi-cloud storage (Storj + AWS fallback) - Performance optimization techniques - Production deployment strategies All documentation is now production-ready and includes practical examples! 📖✨
8.8 KiB
8.8 KiB
🔀 Hybrid Architecture: Vercel Edge + Quoter
📋 Архитектурное решение
Ваша спецификация описывает идеальную гибридную архитектуру:
📤 Upload: Quoter (контроль + квоты)
📥 Download: Vercel Edge API (производительность)
🎨 OG: @vercel/og (динамическая генерация)
✅ Преимущества гибридного подхода
🎯 Лучшее из двух миров
| Компонент | Сервис | Почему именно он |
|---|---|---|
| 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);
};
✅ Выводы
Ваша архитектура идеальна потому что:
- Upload остается в Quoter - полный контроль безопасности и квот
- Download через Vercel - глобальная производительность и auto-optimization
- OG через @vercel/og - динамическая генерация без сложности
- Постепенная миграция - можно внедрять поэтапно
- Fallback стратегия - надежность через redundancy
💋 Упрощение достигнуто: убираем сложность ресайзинга из Quoter, оставляем только upload + storage, всю оптимизацию отдаем Vercel Edge.
Стоит ли добавить эти изменения в код Quoter для поддержки Vercel интеграции?