@rivtor/erasure
v1.1.0
Published
GDPR Article 17 Right to be Forgotten with legal retention engine and dependency graph resolver
Downloads
21
Maintainers
Readme
@rivtor/erasure
Production-ready GDPR Article 17 Right to be Forgotten with legal retention engine
Features
- Legal Retention Engine: Pre-configured retention rules for EU/UK/California jurisdictions
- Dependency Graph Resolver: Intelligent cascading deletes across related tables
- Anonymization Strategies: Hash, tokenize, nullify, randomize, and aggregate options
- Processor Notification Queue: Automatic webhook notifications to Stripe, SendGrid, and more
- Grace Period Management: 30-day grace period with cancellation support
- Comprehensive Audit Trail: Complete logging of all erasure operations
Installation
npm install @rivtor/erasure
# or
yarn add @rivtor/erasure
# or
pnpm add @rivtor/erasureQuick Start
1. Execute Immediate Erasure
import { executeEraseUser } from '@rivtor/erasure/server';
const result = await executeEraseUser('user-123', {
retention_overrides: {
invoices: {
retain_until: '2035-01-01',
reason: 'German tax law (10 years)',
legal_basis: 'legal_obligation',
jurisdiction: 'DE'
}
},
anonymize_instead_of_delete: {
analytics: {
strategy: 'aggregate',
fields: ['user_id', 'ip_address']
}
},
notify_processors: true
});
console.log(result);
// {
// success: true,
// deletedTables: ['users', 'profiles', 'sessions'],
// anonymizedTables: ['analytics_events'],
// retainedTables: ['invoices'],
// notifications: ['stripe', 'sendgrid']
// }2. Schedule Deletion with Grace Period
import { scheduleDeletion } from '@rivtor/erasure/server';
// Schedule for 30 days from now
const deletionId = await scheduleDeletion('user-123', 'user', 30);
// User can cancel within grace period
await cancelScheduledDeletion(deletionId);3. Process Scheduled Deletions
import { processScheduledDeletions } from '@rivtor/erasure/server';
// Call from cron job (e.g., every hour)
const processed = await processScheduledDeletions(10);
console.log(`Processed ${processed} deletions`);4. Check Deletion Status
import { checkDeletionStatus } from '@rivtor/erasure/server';
const { status, tracker } = await checkDeletionStatus('user-123');
console.log(status);
// 'pending' | 'processing' | 'completed' | 'failed' | 'not_found'API Reference
Server Functions
import {
executeEraseUser,
scheduleDeletion,
cancelScheduledDeletion,
processScheduledDeletions,
checkDeletionStatus
} from '@rivtor/erasure/server';
// Execute immediate erasure
await executeEraseUser(
userId: string,
options?: {
retention_overrides?: Record<string, RetentionOverride>;
anonymize_instead_of_delete?: Record<string, AnonymizationConfig>;
notify_processors?: boolean;
external_apis?: ExternalApiConfig[];
}
): Promise<ErasureResult>;
// Schedule deletion with grace period
await scheduleDeletion(
userId: string,
entityType: string,
gracePeriodDays: number,
options?: ErasureOptions
): Promise<string>; // Returns deletionId
// Cancel scheduled deletion
await cancelScheduledDeletion(deletionId: string): Promise<boolean>;
// Process scheduled deletions (for cron jobs)
await processScheduledDeletions(limit?: number): Promise<number>; // Returns count
// Check deletion status
await checkDeletionStatus(
userId: string
): Promise<{
status: 'pending' | 'processing' | 'completed' | 'failed' | 'not_found';
tracker?: ErasureTracker;
}>;Anonymization Strategies
type AnonymizationStrategy =
| 'hash' // One-way hash of the value
| 'tokenize' // Replace with random token
| 'nullify' // Set to NULL
| 'randomize' // Replace with random realistic value
| 'aggregate'; // Aggregate with other records
// Example usage
await executeEraseUser('user-123', {
anonymize_instead_of_delete: {
// Hash email for login records
auth_logs: {
strategy: 'hash',
fields: ['email', 'ip_address']
},
// Nullify PII in analytics
analytics_events: {
strategy: 'nullify',
fields: ['user_agent', 'referrer']
},
// Aggregate user interactions
interactions: {
strategy: 'aggregate',
fields: ['user_id']
}
}
});Retention Overrides
interface RetentionOverride {
retain_until: string; // ISO date string
reason: string; // Legal reason for retention
legal_basis: string; // 'legal_obligation' | 'contract' | 'legitimate_interest'
jurisdiction: string; // Country code (DE, UK, CA, etc.)
}
// Pre-configured retention rules for common jurisdictions
await executeEraseUser('user-123', {
retention_overrides: {
// German tax law (10 years)
invoices: {
retain_until: '2035-01-01',
reason: 'German tax law (10 years)',
legal_basis: 'legal_obligation',
jurisdiction: 'DE'
},
// UK financial records (7 years)
transactions: {
retain_until: '2032-01-01',
reason: 'UK financial regulations',
legal_basis: 'legal_obligation',
jurisdiction: 'UK'
}
}
});Processor Notifications
interface ExternalApiConfig {
name: string;
url: string;
method: 'POST' | 'DELETE';
headers?: Record<string, string>;
body_template?: string;
retry_count?: number;
}
await executeEraseUser('user-123', {
external_apis: [
{
name: 'stripe',
url: 'https://api.stripe.com/v1/customers/{{user_id}}',
method: 'DELETE',
headers: {
'Authorization': `Bearer ${process.env.STRIPE_API_KEY}`
},
retry_count: 3
},
{
name: 'sendgrid',
url: 'https://api.sendgrid.com/v3/marketing/contacts',
method: 'DELETE',
headers: {
'Authorization': `Bearer ${process.env.SENDGRID_API_KEY}`
}
}
]
});Database Schema
-- Scheduled deletions with grace period
CREATE TABLE scheduled_deletions (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
entity_type TEXT NOT NULL,
scheduled_for TIMESTAMPTZ NOT NULL,
status TEXT NOT NULL DEFAULT 'pending',
created_at TIMESTAMPTZ DEFAULT NOW(),
cancelled_at TIMESTAMPTZ,
completed_at TIMESTAMPTZ,
error TEXT,
options JSONB
);
-- Comprehensive erasure audit logs
CREATE TABLE erasure_audit_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
entity_type TEXT NOT NULL,
status TEXT NOT NULL,
started_at TIMESTAMPTZ NOT NULL,
completed_at TIMESTAMPTZ,
deleted_tables TEXT[] NOT NULL DEFAULT '{}',
anonymized_tables TEXT[] NOT NULL DEFAULT '{}',
retained_tables TEXT[] NOT NULL DEFAULT '{}',
retention_overrides JSONB,
external_api_calls JSONB,
errors JSONB,
requested_by TEXT,
ip_address TEXT
);
-- Indexes for efficient queries
CREATE INDEX idx_scheduled_deletions_user ON scheduled_deletions(user_id);
CREATE INDEX idx_scheduled_deletions_status ON scheduled_deletions(status);
CREATE INDEX idx_scheduled_deletions_scheduled_for ON scheduled_deletions(scheduled_for);
CREATE INDEX idx_erasure_audit_logs_user ON erasure_audit_logs(user_id);
CREATE INDEX idx_erasure_audit_logs_status ON erasure_audit_logs(status);Configuration
import { configureErasure } from '@rivtor/erasure/server';
configureErasure({
// Default grace period in days
defaultGracePeriodDays: 30,
// Default retention rules by jurisdiction
defaultRetention: {
EU: {
invoices: { years: 10 },
tax_records: { years: 10 },
contracts: { years: 5 }
},
UK: {
financial_records: { years: 7 },
invoices: { years: 6 }
},
US: {
tax_records: { years: 7 },
employment_records: { years: 7 }
}
},
// Default anonymization strategy
defaultAnonymization: {
strategy: 'hash',
fields: ['email', 'name', 'phone']
},
// External API retry settings
retryConfig: {
maxRetries: 3,
backoffMs: 1000,
timeoutMs: 30000
}
});Best Practices
- Always Use Grace Periods: Give users time to change their mind
- Document Retention: Keep clear records of why data is retained
- Test Anonymization: Verify anonymization strategies before production
- Monitor External APIs: Track processor notification success rates
- Regular Audit Reviews: Review erasure audit logs periodically
Legal Compliance
This package helps comply with:
- GDPR Article 17: Right to erasure (right to be forgotten)
- CCPA: Right to delete
- UK GDPR: Data deletion requirements
- Various Tax Laws: Legal retention obligations
License
MIT
Made with ❤️ by Rivtor
