
Some checks failed
CI Pipeline / Setup Dependencies (push) Has been cancelled
CI Pipeline / Check Dependency Updates (push) Has been cancelled
CI Pipeline / Setup Dependencies (pull_request) Has been cancelled
CI Pipeline / Check Dependency Updates (pull_request) Has been cancelled
CI Pipeline / Lint & Format Check (push) Has been cancelled
CI Pipeline / Unit Tests (push) Has been cancelled
CI Pipeline / Integration Tests (push) Has been cancelled
CI Pipeline / Build Application (push) Has been cancelled
CI Pipeline / Docker Build & Test (push) Has been cancelled
CI Pipeline / Security Scan (push) Has been cancelled
CI Pipeline / Deployment Readiness (push) Has been cancelled
CI Pipeline / Lint & Format Check (pull_request) Has been cancelled
CI Pipeline / Unit Tests (pull_request) Has been cancelled
CI Pipeline / Integration Tests (pull_request) Has been cancelled
CI Pipeline / Build Application (pull_request) Has been cancelled
CI Pipeline / Docker Build & Test (pull_request) Has been cancelled
CI Pipeline / Security Scan (pull_request) Has been cancelled
CI Pipeline / Deployment Readiness (pull_request) Has been cancelled
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>
298 lines
No EOL
6.7 KiB
JavaScript
298 lines
No EOL
6.7 KiB
JavaScript
/**
|
|
* 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;
|
|
} |