2025-10-06 15:27:01 +02:00
|
|
|
// ================================================================
|
|
|
|
|
// frontend/src/api/services/auth.ts
|
|
|
|
|
// ================================================================
|
2025-09-05 17:49:48 +02:00
|
|
|
/**
|
2025-10-06 15:27:01 +02:00
|
|
|
* Auth Service - Complete backend alignment
|
|
|
|
|
*
|
|
|
|
|
* Backend API structure (3-tier architecture):
|
|
|
|
|
* - ATOMIC: users.py
|
|
|
|
|
* - OPERATIONS: auth_operations.py, onboarding_progress.py
|
|
|
|
|
*
|
|
|
|
|
* Last Updated: 2025-10-05
|
|
|
|
|
* Status: ✅ Complete - Zero drift with backend
|
2025-09-05 17:49:48 +02:00
|
|
|
*/
|
|
|
|
|
import { apiClient } from '../client';
|
|
|
|
|
import {
|
|
|
|
|
UserRegistration,
|
|
|
|
|
UserLogin,
|
|
|
|
|
TokenResponse,
|
|
|
|
|
RefreshTokenRequest,
|
|
|
|
|
PasswordChange,
|
|
|
|
|
PasswordReset,
|
|
|
|
|
UserResponse,
|
|
|
|
|
UserUpdate,
|
|
|
|
|
TokenVerificationResponse,
|
|
|
|
|
AuthHealthResponse,
|
|
|
|
|
} from '../types/auth';
|
|
|
|
|
|
|
|
|
|
export class AuthService {
|
|
|
|
|
private readonly baseUrl = '/auth';
|
|
|
|
|
|
2025-10-06 15:27:01 +02:00
|
|
|
// ===================================================================
|
|
|
|
|
// OPERATIONS: Authentication
|
|
|
|
|
// Backend: services/auth/app/api/auth_operations.py
|
|
|
|
|
// ===================================================================
|
|
|
|
|
|
2025-09-05 17:49:48 +02:00
|
|
|
async register(userData: UserRegistration): Promise<TokenResponse> {
|
|
|
|
|
return apiClient.post<TokenResponse>(`${this.baseUrl}/register`, userData);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-13 22:22:38 +01:00
|
|
|
async registerWithSubscription(userData: UserRegistration): Promise<UserRegistrationWithSubscriptionResponse> {
|
|
|
|
|
return apiClient.post<UserRegistrationWithSubscriptionResponse>(`${this.baseUrl}/register-with-subscription`, userData);
|
|
|
|
|
}
|
|
|
|
|
|
2026-01-14 13:15:48 +01:00
|
|
|
async completeRegistrationAfterSetupIntent(completionData: {
|
|
|
|
|
email: string;
|
|
|
|
|
password: string;
|
|
|
|
|
full_name: string;
|
|
|
|
|
setup_intent_id: string;
|
|
|
|
|
plan_id: string;
|
|
|
|
|
payment_method_id: string;
|
|
|
|
|
billing_interval: 'monthly' | 'yearly';
|
|
|
|
|
coupon_code?: string;
|
|
|
|
|
}): Promise<TokenResponse> {
|
|
|
|
|
return apiClient.post<TokenResponse>(`${this.baseUrl}/complete-registration-after-setup-intent`, completionData);
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-05 17:49:48 +02:00
|
|
|
async login(loginData: UserLogin): Promise<TokenResponse> {
|
|
|
|
|
return apiClient.post<TokenResponse>(`${this.baseUrl}/login`, loginData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async refreshToken(refreshToken: string): Promise<TokenResponse> {
|
|
|
|
|
const refreshData: RefreshTokenRequest = { refresh_token: refreshToken };
|
|
|
|
|
return apiClient.post<TokenResponse>(`${this.baseUrl}/refresh`, refreshData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async verifyToken(token?: string): Promise<TokenVerificationResponse> {
|
|
|
|
|
// If token is provided, temporarily set it; otherwise use current token
|
|
|
|
|
const currentToken = apiClient.getAuthToken();
|
|
|
|
|
if (token && token !== currentToken) {
|
|
|
|
|
apiClient.setAuthToken(token);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const response = await apiClient.post<TokenVerificationResponse>(`${this.baseUrl}/verify`);
|
|
|
|
|
|
|
|
|
|
// Restore original token if we temporarily changed it
|
|
|
|
|
if (token && token !== currentToken) {
|
|
|
|
|
apiClient.setAuthToken(currentToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return response;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async logout(refreshToken: string): Promise<{ message: string }> {
|
|
|
|
|
const refreshData: RefreshTokenRequest = { refresh_token: refreshToken };
|
|
|
|
|
return apiClient.post<{ message: string }>(`${this.baseUrl}/logout`, refreshData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async changePassword(passwordData: PasswordChange): Promise<{ message: string }> {
|
|
|
|
|
return apiClient.post<{ message: string }>(`${this.baseUrl}/change-password`, passwordData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async resetPassword(resetData: PasswordReset): Promise<{ message: string }> {
|
|
|
|
|
return apiClient.post<{ message: string }>(`${this.baseUrl}/reset-password`, resetData);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-06 15:27:01 +02:00
|
|
|
// ===================================================================
|
2025-10-27 16:33:26 +01:00
|
|
|
// User Profile (authenticated)
|
|
|
|
|
// Backend: services/auth/app/api/auth_operations.py
|
2025-10-06 15:27:01 +02:00
|
|
|
// ===================================================================
|
|
|
|
|
|
2025-09-05 17:49:48 +02:00
|
|
|
async getProfile(): Promise<UserResponse> {
|
2025-10-27 16:33:26 +01:00
|
|
|
return apiClient.get<UserResponse>(`${this.baseUrl}/me`);
|
2025-09-05 17:49:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async updateProfile(updateData: UserUpdate): Promise<UserResponse> {
|
2025-10-27 16:33:26 +01:00
|
|
|
return apiClient.put<UserResponse>(`${this.baseUrl}/me`, updateData);
|
2025-09-05 17:49:48 +02:00
|
|
|
}
|
|
|
|
|
|
2025-10-06 15:27:01 +02:00
|
|
|
// ===================================================================
|
|
|
|
|
// OPERATIONS: Email Verification
|
|
|
|
|
// Backend: services/auth/app/api/auth_operations.py
|
|
|
|
|
// ===================================================================
|
|
|
|
|
|
2025-09-05 17:49:48 +02:00
|
|
|
async verifyEmail(
|
|
|
|
|
userId: string,
|
|
|
|
|
verificationToken: string
|
|
|
|
|
): Promise<{ message: string }> {
|
|
|
|
|
return apiClient.post<{ message: string }>(`${this.baseUrl}/verify-email`, {
|
|
|
|
|
user_id: userId,
|
|
|
|
|
verification_token: verificationToken,
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-27 16:33:26 +01:00
|
|
|
// ===================================================================
|
|
|
|
|
// Account Management (self-service)
|
|
|
|
|
// Backend: services/auth/app/api/account_deletion.py
|
|
|
|
|
// ===================================================================
|
|
|
|
|
|
|
|
|
|
async deleteAccount(confirmEmail: string, password: string, reason?: string): Promise<{ message: string; deletion_date: string }> {
|
|
|
|
|
return apiClient.delete(`${this.baseUrl}/me/account`, {
|
|
|
|
|
data: {
|
|
|
|
|
confirm_email: confirmEmail,
|
|
|
|
|
password: password,
|
|
|
|
|
reason: reason || ''
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getAccountDeletionInfo(): Promise<any> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/me/account/deletion-info`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===================================================================
|
|
|
|
|
// GDPR Consent Management
|
|
|
|
|
// Backend: services/auth/app/api/consent.py
|
|
|
|
|
// ===================================================================
|
|
|
|
|
|
|
|
|
|
async recordConsent(consentData: {
|
|
|
|
|
terms_accepted: boolean;
|
|
|
|
|
privacy_accepted: boolean;
|
|
|
|
|
marketing_consent?: boolean;
|
|
|
|
|
analytics_consent?: boolean;
|
|
|
|
|
consent_method: string;
|
|
|
|
|
consent_version?: string;
|
|
|
|
|
}): Promise<any> {
|
|
|
|
|
return apiClient.post(`${this.baseUrl}/me/consent`, consentData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getCurrentConsent(): Promise<any> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/me/consent/current`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getConsentHistory(): Promise<any[]> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/me/consent/history`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async updateConsent(consentData: {
|
|
|
|
|
terms_accepted: boolean;
|
|
|
|
|
privacy_accepted: boolean;
|
|
|
|
|
marketing_consent?: boolean;
|
|
|
|
|
analytics_consent?: boolean;
|
|
|
|
|
consent_method: string;
|
|
|
|
|
consent_version?: string;
|
|
|
|
|
}): Promise<any> {
|
|
|
|
|
return apiClient.put(`${this.baseUrl}/me/consent`, consentData);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async withdrawConsent(): Promise<{ message: string; withdrawn_count: number }> {
|
|
|
|
|
return apiClient.post(`${this.baseUrl}/me/consent/withdraw`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===================================================================
|
|
|
|
|
// Data Export (GDPR)
|
|
|
|
|
// Backend: services/auth/app/api/data_export.py
|
|
|
|
|
// ===================================================================
|
|
|
|
|
|
|
|
|
|
async exportMyData(): Promise<any> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/me/export`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getExportSummary(): Promise<any> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/me/export/summary`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===================================================================
|
|
|
|
|
// Onboarding Progress
|
|
|
|
|
// Backend: services/auth/app/api/onboarding_progress.py
|
|
|
|
|
// ===================================================================
|
|
|
|
|
|
|
|
|
|
async getOnboardingProgress(): Promise<any> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/me/onboarding/progress`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async updateOnboardingStep(stepName: string, completed: boolean, data?: any): Promise<any> {
|
|
|
|
|
return apiClient.put(`${this.baseUrl}/me/onboarding/step`, {
|
|
|
|
|
step_name: stepName,
|
|
|
|
|
completed: completed,
|
|
|
|
|
data: data
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async getNextOnboardingStep(): Promise<{ step: string }> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/me/onboarding/next-step`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async canAccessOnboardingStep(stepName: string): Promise<{ can_access: boolean }> {
|
|
|
|
|
return apiClient.get(`${this.baseUrl}/me/onboarding/can-access/${stepName}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async completeOnboarding(): Promise<{ success: boolean; message: string }> {
|
|
|
|
|
return apiClient.post(`${this.baseUrl}/me/onboarding/complete`);
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-06 15:27:01 +02:00
|
|
|
// ===================================================================
|
|
|
|
|
// Health Check
|
|
|
|
|
// ===================================================================
|
|
|
|
|
|
2025-09-05 17:49:48 +02:00
|
|
|
async healthCheck(): Promise<AuthHealthResponse> {
|
|
|
|
|
return apiClient.get<AuthHealthResponse>(`${this.baseUrl}/health`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const authService = new AuthService();
|