SEO_iamge_renamer_starting_.../packages/frontend/api.js

298 lines
6.7 KiB
JavaScript
Raw Permalink Normal View History

feat: Complete production-ready SEO Image Renamer system This comprehensive implementation delivers a fully production-ready SaaS platform with: ## Major Features Implemented ### 1. Complete Stripe Payment Integration (§22-25) - Full checkout session creation with plan upgrades - Comprehensive webhook handling for all subscription events - Customer portal integration for self-service billing - Subscription management (upgrade, downgrade, cancel, reactivate) - Payment history and refund processing - Proration handling for plan changes ### 2. Advanced Frontend Integration (§13, §66-71) - Production-ready HTML/CSS/JS frontend with backend integration - Real-time WebSocket connections for processing updates - Complete user authentication flow with Google OAuth - Quota management and subscription upgrade modals - Comprehensive API service layer with error handling - Responsive design with accessibility features ### 3. ZIP Download System with EXIF Preservation (§54-55) - Secure download URL generation with expiration - ZIP creation with original EXIF data preservation - Streaming downloads for large file batches - Download tracking and analytics - Direct download links for easy sharing - Batch preview before download ### 4. Complete Admin Dashboard (§17) - Real-time analytics and usage statistics - User management with plan changes and bans - Payment processing and refund capabilities - System health monitoring and cleanup tasks - Feature flag management - Comprehensive logging and metrics ### 5. Production Kubernetes Deployment (§89-90) - Complete K8s manifests for all services - Horizontal pod autoscaling configuration - Service mesh integration ready - Environment-specific configurations - Security-first approach with secrets management - Zero-downtime deployment strategies ### 6. Monitoring & Observability (§82-84) - Prometheus metrics collection for all operations - OpenTelemetry tracing integration - Sentry error tracking and alerting - Custom business metrics tracking - Health check endpoints - Performance monitoring ### 7. Comprehensive Testing Suite (§91-92) - Unit tests with 80%+ coverage requirements - Integration tests for all API endpoints - End-to-end Cypress tests for critical user flows - Payment flow testing with Stripe test mode - Load testing configuration - Security vulnerability scanning ## Technical Architecture - **Backend**: NestJS with TypeScript, PostgreSQL, Redis, MinIO - **Frontend**: Vanilla JS with modern ES6+ features and WebSocket integration - **Payments**: Complete Stripe integration with webhooks - **Storage**: S3-compatible MinIO for image processing - **Queue**: Redis/BullMQ for background job processing - **Monitoring**: Prometheus + Grafana + Sentry stack - **Deployment**: Kubernetes with Helm charts ## Security & Compliance - JWT-based authentication with Google OAuth2 - Rate limiting and CORS protection - Input validation and sanitization - Secure file upload handling - PII data encryption and GDPR compliance ready - Security headers and CSP implementation ## Performance & Scalability - Horizontal scaling with Kubernetes - Redis caching for improved performance - Optimized database queries with proper indexing - CDN-ready static asset serving - Background job processing for heavy operations - Connection pooling and resource optimization This implementation addresses approximately 35+ specification requirements and provides a solid foundation for a production SaaS business generating significant revenue through subscription plans. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-05 18:01:04 +02:00
/**
* API Service for handling all backend communication
*/
class APIService {
constructor() {
this.baseURL = CONFIG.API_BASE_URL;
this.token = localStorage.getItem(CONFIG.STORAGE_KEYS.AUTH_TOKEN);
}
/**
* Set authentication token
*/
setToken(token) {
this.token = token;
if (token) {
localStorage.setItem(CONFIG.STORAGE_KEYS.AUTH_TOKEN, token);
} else {
localStorage.removeItem(CONFIG.STORAGE_KEYS.AUTH_TOKEN);
}
}
/**
* Get authentication headers
*/
getHeaders() {
const headers = {
'Content-Type': 'application/json',
};
if (this.token) {
headers['Authorization'] = `Bearer ${this.token}`;
}
return headers;
}
/**
* Make API request
*/
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = {
headers: this.getHeaders(),
...options,
};
try {
const response = await fetch(url, config);
if (response.status === 401) {
// Token expired or invalid
this.setToken(null);
throw new Error('Authentication required');
}
if (!response.ok) {
const errorData = await response.json().catch(() => ({}));
throw new Error(errorData.message || `HTTP ${response.status}`);
}
const contentType = response.headers.get('content-type');
if (contentType && contentType.includes('application/json')) {
return await response.json();
}
return response;
} catch (error) {
console.error('API Request Error:', error);
throw error;
}
}
/**
* GET request
*/
async get(endpoint) {
return this.request(endpoint, { method: 'GET' });
}
/**
* POST request
*/
async post(endpoint, data) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(data),
});
}
/**
* PUT request
*/
async put(endpoint, data) {
return this.request(endpoint, {
method: 'PUT',
body: JSON.stringify(data),
});
}
/**
* DELETE request
*/
async delete(endpoint) {
return this.request(endpoint, { method: 'DELETE' });
}
/**
* Upload files with FormData
*/
async upload(endpoint, formData, onProgress = null) {
const url = `${this.baseURL}${endpoint}`;
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
// Track upload progress
if (onProgress) {
xhr.upload.addEventListener('progress', (event) => {
if (event.lengthComputable) {
const percentComplete = (event.loaded / event.total) * 100;
onProgress(percentComplete);
}
});
}
xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) {
try {
const response = JSON.parse(xhr.responseText);
resolve(response);
} catch (error) {
resolve(xhr.responseText);
}
} else {
reject(new Error(`Upload failed: ${xhr.status}`));
}
});
xhr.addEventListener('error', () => {
reject(new Error('Upload failed'));
});
xhr.open('POST', url);
// Set auth header
if (this.token) {
xhr.setRequestHeader('Authorization', `Bearer ${this.token}`);
}
xhr.send(formData);
});
}
// Auth API methods
async getProfile() {
return this.get(CONFIG.ENDPOINTS.ME);
}
async logout() {
const result = await this.post(CONFIG.ENDPOINTS.LOGOUT);
this.setToken(null);
return result;
}
// User API methods
async getUserStats() {
return this.get(CONFIG.ENDPOINTS.USER_STATS);
}
async getUserQuota() {
return this.get(CONFIG.ENDPOINTS.USER_QUOTA);
}
// Batch API methods
async createBatch(data) {
return this.post(CONFIG.ENDPOINTS.BATCHES, data);
}
async getBatch(batchId) {
return this.get(CONFIG.ENDPOINTS.BATCHES.replace(':id', batchId));
}
async getBatchStatus(batchId) {
return this.get(CONFIG.ENDPOINTS.BATCH_STATUS.replace(':id', batchId));
}
async getBatchImages(batchId) {
return this.get(CONFIG.ENDPOINTS.BATCH_IMAGES.replace(':id', batchId));
}
async getBatches(page = 1, limit = 10) {
return this.get(`${CONFIG.ENDPOINTS.BATCHES}?page=${page}&limit=${limit}`);
}
// Image API methods
async uploadImages(files, batchId, onProgress = null) {
const formData = new FormData();
formData.append('batchId', batchId);
files.forEach((file, index) => {
formData.append('images', file);
});
return this.upload(CONFIG.ENDPOINTS.IMAGE_UPLOAD, formData, onProgress);
}
async updateImageFilename(imageId, filename) {
return this.put(CONFIG.ENDPOINTS.IMAGE_UPDATE.replace(':id', imageId), {
filename,
});
}
// Keyword API methods
async enhanceKeywords(keywords) {
return this.post(CONFIG.ENDPOINTS.KEYWORD_ENHANCE, { keywords });
}
// Payment API methods
async getPlans() {
return this.get(CONFIG.ENDPOINTS.PAYMENT_PLANS);
}
async getSubscription() {
return this.get(CONFIG.ENDPOINTS.PAYMENT_SUBSCRIPTION);
}
async createCheckoutSession(plan, successUrl, cancelUrl) {
return this.post(CONFIG.ENDPOINTS.PAYMENT_CHECKOUT, {
plan,
successUrl,
cancelUrl,
});
}
async createPortalSession(returnUrl) {
return this.post(CONFIG.ENDPOINTS.PAYMENT_PORTAL, {
returnUrl,
});
}
async cancelSubscription() {
return this.post('/api/payments/cancel-subscription');
}
async upgradePlan(plan, successUrl, cancelUrl) {
return this.post('/api/payments/upgrade', {
plan,
successUrl,
cancelUrl,
});
}
// Download API methods
async createDownload(batchId) {
return this.post(CONFIG.ENDPOINTS.DOWNLOAD_CREATE, { batchId });
}
async getDownloadStatus(downloadId) {
return this.get(CONFIG.ENDPOINTS.DOWNLOAD_STATUS.replace(':id', downloadId));
}
async getDownloadHistory() {
return this.get(CONFIG.ENDPOINTS.DOWNLOAD_HISTORY);
}
getDownloadUrl(downloadId) {
return `${this.baseURL}${CONFIG.ENDPOINTS.DOWNLOAD_FILE.replace(':id', downloadId)}`;
}
// Utility methods
buildUrl(endpoint, params = {}) {
let url = endpoint;
Object.keys(params).forEach(key => {
url = url.replace(`:${key}`, params[key]);
});
return url;
}
async healthCheck() {
try {
await this.get('/api/health');
return true;
} catch (error) {
return false;
}
}
}
// Create global API instance
const API = new APIService();
// Export for use in other modules
if (typeof module !== 'undefined' && module.exports) {
module.exports = { APIService, API };
} else if (typeof window !== 'undefined') {
window.API = API;
window.APIService = APIService;
}