Improve GDPR implementation

This commit is contained in:
Urtzi Alfaro
2025-10-16 07:28:04 +02:00
parent dbb48d8e2c
commit b6cb800758
37 changed files with 4876 additions and 307 deletions

View File

@@ -0,0 +1,88 @@
// ================================================================
// frontend/src/api/services/consent.ts
// ================================================================
/**
* Consent Service - GDPR Compliance
*
* Backend API: services/auth/app/api/consent.py
*
* Last Updated: 2025-10-16
*/
import { apiClient } from '../client';
export interface ConsentRequest {
terms_accepted: boolean;
privacy_accepted: boolean;
marketing_consent?: boolean;
analytics_consent?: boolean;
consent_method: 'registration' | 'settings' | 'cookie_banner';
consent_version?: string;
}
export interface ConsentResponse {
id: string;
user_id: string;
terms_accepted: boolean;
privacy_accepted: boolean;
marketing_consent: boolean;
analytics_consent: boolean;
consent_version: string;
consent_method: string;
consented_at: string;
withdrawn_at: string | null;
}
export interface ConsentHistoryResponse {
id: string;
user_id: string;
action: string;
consent_snapshot: Record<string, any>;
created_at: string;
}
export class ConsentService {
private readonly baseUrl = '/auth';
/**
* Record user consent for data processing
* GDPR Article 7 - Conditions for consent
*/
async recordConsent(consentData: ConsentRequest): Promise<ConsentResponse> {
return apiClient.post<ConsentResponse>(`${this.baseUrl}/consent`, consentData);
}
/**
* Get current active consent for user
*/
async getCurrentConsent(): Promise<ConsentResponse | null> {
return apiClient.get<ConsentResponse | null>(`${this.baseUrl}/consent/current`);
}
/**
* Get complete consent history for user
* GDPR Article 7(1) - Demonstrating consent
*/
async getConsentHistory(): Promise<ConsentHistoryResponse[]> {
return apiClient.get<ConsentHistoryResponse[]>(`${this.baseUrl}/consent/history`);
}
/**
* Update user consent preferences
* GDPR Article 7(3) - Withdrawal of consent
*/
async updateConsent(consentData: ConsentRequest): Promise<ConsentResponse> {
return apiClient.put<ConsentResponse>(`${this.baseUrl}/consent`, consentData);
}
/**
* Withdraw all consent
* GDPR Article 7(3) - Right to withdraw consent
*/
async withdrawConsent(): Promise<{ message: string; withdrawn_count: number }> {
return apiClient.post<{ message: string; withdrawn_count: number }>(
`${this.baseUrl}/consent/withdraw`
);
}
}
export const consentService = new ConsentService();

View File

@@ -299,6 +299,53 @@ export class SubscriptionService {
doesAnalyticsLevelMeetMinimum(level: AnalyticsLevel, minimumRequired: AnalyticsLevel): boolean {
return ANALYTICS_HIERARCHY[level] >= ANALYTICS_HIERARCHY[minimumRequired];
}
/**
* Cancel subscription - Downgrade to read-only mode
*/
async cancelSubscription(tenantId: string, reason?: string): Promise<{
success: boolean;
message: string;
status: string;
cancellation_effective_date: string;
days_remaining: number;
read_only_mode_starts: string;
}> {
return apiClient.post('/subscriptions/cancel', {
tenant_id: tenantId,
reason: reason || ''
});
}
/**
* Reactivate a cancelled or inactive subscription
*/
async reactivateSubscription(tenantId: string, plan: string = 'starter'): Promise<{
success: boolean;
message: string;
status: string;
plan: string;
next_billing_date: string | null;
}> {
return apiClient.post('/subscriptions/reactivate', {
tenant_id: tenantId,
plan
});
}
/**
* Get subscription status including read-only mode info
*/
async getSubscriptionStatus(tenantId: string): Promise<{
tenant_id: string;
status: string;
plan: string;
is_read_only: boolean;
cancellation_effective_date: string | null;
days_until_inactive: number | null;
}> {
return apiClient.get(`/subscriptions/${tenantId}/status`);
}
}
export const subscriptionService = new SubscriptionService();