Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 7 additions & 23 deletions backend/services/gdpr.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,13 @@ export interface UserConsent {

export const exportUserData = async (userId: string) => {
console.log(`Exporting data for user: ${userId}`);

// In a real scenario, this would query multiple tables/collections
const userData = {
profile: { id: userId, email: 'user@example.com', registeredAt: '2026-01-01' },
subscriptions: [
{ id: 'sub_1', name: 'Netflix', amount: 15.99, status: 'active' }
],
billingHistory: [
{ id: 'tx_1', date: '2026-04-20', amount: 15.99, status: 'completed' }
],
consentLogs: [
{ type: 'analytics', status: 'granted', date: '2026-01-01' }
],
subscriptions: [{ id: 'sub_1', name: 'Netflix', amount: 15.99, status: 'active' }],
billingHistory: [{ id: 'tx_1', date: '2026-04-20', amount: 15.99, status: 'completed' }],
consentLogs: [{ type: 'analytics', status: 'granted', date: '2026-01-01' }],
};

return JSON.stringify(userData, null, 2);
Expand All @@ -42,23 +36,13 @@ export const deleteUserData = async (userId: string, permanent: boolean = false)
// Hard delete logic across all services
// await SubscriptionModel.deleteMany({ userId });
// await ProfileModel.deleteOne({ userId });

return { success: true, message: 'User data permanently deleted' };
};

export const anonymizeUserData = async (userId: string) => {
console.log(`Anonymizing data for user: ${userId}`);

// Replace sensitive identifiers with null/dummy values
const updates = {
email: `deleted-${Date.now()}@anonymized.invalid`,
name: 'Anonymized User',
address: null,
phone: null,
};

// await ProfileModel.updateOne({ userId }, updates);

return { success: true, message: 'User data has been anonymized' };
};

Expand All @@ -70,8 +54,8 @@ export const updateConsent = async (userId: string, preferences: Partial<UserCon

// Log consent change for audit trail
console.log(`Consent updated for ${userId}:`, newConsent);

// await ConsentAuditModel.create({ userId, ...newConsent });

return newConsent;
};
65 changes: 65 additions & 0 deletions backend/services/logging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
export type LogLevel = 'debug' | 'info' | 'warn' | 'error';

const LOG_LEVEL_PRIORITY: Record<LogLevel, number> = {
debug: 0,
info: 1,
warn: 2,
error: 3,
};

// Change this via env later
const CURRENT_LEVEL: LogLevel = __DEV__ ? 'debug' : 'info';

// Correlation ID generator (simple version)
const generateId = () => {
return Math.random().toString(36).substring(2) + Date.now().toString(36);
};

export interface LogContext {
[key: string]: any;
correlationId?: string;
}

function shouldLog(level: LogLevel) {
return LOG_LEVEL_PRIORITY[level] >= LOG_LEVEL_PRIORITY[CURRENT_LEVEL];
}

function formatLog(level: LogLevel, message: string, context?: LogContext) {
return {
level,
message,
timestamp: new Date().toISOString(),
...context,
};
}

function sendToConsole(logEntry: any) {
console.log(JSON.stringify(logEntry, null, 2));
}

// future: plug Sentry / API here
async function sendToRemote(_logEntry: any) {
// Example:
// await fetch("https://your-api/logs", { method: "POST", body: JSON.stringify(logEntry) });
}

function log(level: LogLevel, message: string, context?: LogContext) {
if (!shouldLog(level)) return;

const logEntry = formatLog(level, message, context);

sendToConsole(logEntry);

if (level === 'error') {
sendToRemote(logEntry);
}
}

export const logger = {
debug: (msg: string, ctx?: LogContext) => log('debug', msg, ctx),
info: (msg: string, ctx?: LogContext) => log('info', msg, ctx),
warn: (msg: string, ctx?: LogContext) => log('warn', msg, ctx),
error: (msg: string, ctx?: LogContext) => log('error', msg, ctx),

createCorrelationId: generateId,
};
4 changes: 2 additions & 2 deletions backend/tests/load/stress-wrapper.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
/**
* Backend Load Test Wrapper
* This script can be used to trigger k6 tests from a backend context or
* This script can be used to trigger k6 tests from a backend context or
* to provide a wrapper for internal stress testing of specific modules.
*/

const { spawn } = require('child_process');

function runLoadTest(scenario = 'subscription') {
console.log(`Starting load test for scenario: ${scenario}...`);

const k6 = spawn('k6', ['run', '-e', `SCENARIO=${scenario}`, '../../load-tests/run.js']);

k6.stdout.on('data', (data) => {
Expand Down