Claude-code-plugins salesforce-data-handling
install
source · Clone the upstream repo
git clone https://github.com/jeremylongshore/claude-code-plugins-plus-skills
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/jeremylongshore/claude-code-plugins-plus-skills "$T" && mkdir -p ~/.claude/skills && cp -r "$T/plugins/saas-packs/salesforce-pack/skills/salesforce-data-handling" ~/.claude/skills/jeremylongshore-claude-code-plugins-salesforce-data-handling && rm -rf "$T"
manifest:
plugins/saas-packs/salesforce-pack/skills/salesforce-data-handling/SKILL.mdsource content
Salesforce Data Handling
Overview
Handle sensitive data correctly when integrating with Salesforce: PII classification, GDPR/CCPA compliance with Salesforce's Individual object, data retention, and field-level encryption.
Prerequisites
- Understanding of GDPR/CCPA requirements
- Salesforce org with data classification enabled (Setup > Data Classification)
- For encryption: Salesforce Shield license (Platform Encryption)
Instructions
Step 1: Salesforce Data Classification
// Salesforce has built-in data classification on fields // Setup > Object Manager > [Object] > Fields > [Field] > Edit > Data Sensitivity Level // Query field classification metadata const conn = await getConnection(); const contactMeta = await conn.sobject('Contact').describe(); const sensitiveFields = contactMeta.fields .filter((f: any) => f.compoundFieldName === null) // Skip compound fields .map((f: any) => ({ name: f.name, label: f.label, type: f.type, encrypted: f.encrypted || false, // Check custom data sensitivity via field metadata })); // PII fields in standard Salesforce objects const PII_FIELDS: Record<string, string[]> = { Contact: ['FirstName', 'LastName', 'Email', 'Phone', 'MailingAddress', 'Birthdate'], Lead: ['FirstName', 'LastName', 'Email', 'Phone', 'Company'], Account: ['Phone', 'Website'], // Less PII, but may contain it User: ['Email', 'Phone', 'Username'], Case: ['SuppliedEmail', 'SuppliedName', 'SuppliedPhone'], };
Step 2: GDPR — Individual Object & Consent
// Salesforce has a built-in "Individual" object for GDPR consent tracking // Setup > Data Protection and Privacy > Enable Individual object // Link Contact to Individual for consent tracking await conn.sobject('Individual').create({ FirstName: 'Jane', LastName: 'Smith', HasOptedOutTracking: false, HasOptedOutProcessing: false, HasOptedOutSolicit: true, }); // Check consent before processing const contact = await conn.query(` SELECT Id, FirstName, LastName, Email, Individual.HasOptedOutTracking, Individual.HasOptedOutProcessing FROM Contact WHERE Id = '003xxxxxxxxxxxx' `); const individual = contact.records[0]?.Individual; if (individual?.HasOptedOutProcessing) { console.log('Contact has opted out of data processing — skip'); }
Step 3: Data Subject Access Request (DSAR)
// GDPR Article 15: Right of Access async function exportContactData(contactId: string): Promise<object> { const conn = await getConnection(); // Gather all data related to this contact const [contact, cases, activities, opportunities] = await Promise.all([ conn.query(` SELECT FIELDS(ALL) FROM Contact WHERE Id = '${contactId}' LIMIT 1 `), conn.query(` SELECT Id, Subject, Description, CreatedDate, Status FROM Case WHERE ContactId = '${contactId}' `), conn.query(` SELECT Id, Subject, ActivityDate, Description FROM Task WHERE WhoId = '${contactId}' `), conn.query(` SELECT Id, Name, StageName, Amount FROM Opportunity WHERE Id IN ( SELECT OpportunityId FROM OpportunityContactRole WHERE ContactId = '${contactId}' ) `), ]); return { exportDate: new Date().toISOString(), subject: 'Data Subject Access Request', contact: contact.records[0], cases: cases.records, activities: activities.records, opportunities: opportunities.records, }; }
Step 4: Right to Deletion (Right to be Forgotten)
// GDPR Article 17: Right to Erasure async function deleteContactData(contactId: string): Promise<void> { const conn = await getConnection(); // 1. Delete related records first (due to lookup relationships) const tasks = await conn.query(`SELECT Id FROM Task WHERE WhoId = '${contactId}'`); if (tasks.records.length > 0) { await conn.sobject('Task').destroy(tasks.records.map((t: any) => t.Id)); } // 2. Delete the contact await conn.sobject('Contact').destroy(contactId); // 3. Audit log (required — don't delete this) await conn.sobject('Integration_Log__c').create({ Action__c: 'GDPR_DELETION', Record_Id__c: contactId, Object_Type__c: 'Contact', Timestamp__c: new Date().toISOString(), }); // 4. Delete from local caches/databases too console.log(`Contact ${contactId} deleted from Salesforce (GDPR erasure)`); }
Step 5: Data Redaction in Logs
// NEVER log raw Salesforce records containing PII function redactSfRecord(record: Record<string, any>, objectType: string): Record<string, any> { const piiFields = PII_FIELDS[objectType] || []; const redacted = { ...record }; for (const field of piiFields) { if (redacted[field]) { redacted[field] = '[REDACTED]'; } } return redacted; } // Usage in logging const contacts = await conn.query('SELECT Id, FirstName, LastName, Email FROM Contact LIMIT 5'); for (const contact of contacts.records) { console.log('Processing:', redactSfRecord(contact, 'Contact')); // Logs: { Id: '003xx', FirstName: '[REDACTED]', LastName: '[REDACTED]', Email: '[REDACTED]' } }
Step 6: Salesforce Shield Platform Encryption
For field-level encryption at rest (Salesforce Shield license required): Setup > Platform Encryption > Encryption Policy: - Encrypt: Contact.Email, Contact.Phone, Lead.Email - Key Management: Salesforce-managed or customer-managed (BYOK) Limitations of encrypted fields: - Cannot use in WHERE clause (use deterministic encryption for filters) - Cannot use in ORDER BY - Cannot use in aggregate functions - SOQL LIKE operator not supported on encrypted fields
Output
- Data classification for PII fields documented
- GDPR consent tracking via Individual object
- DSAR export function for data subject access
- Right to deletion with audit trail
- Log redaction preventing PII exposure
Error Handling
| Issue | Cause | Solution |
|---|---|---|
| Individual object not enabled | Setup > Data Protection > Enable Individual |
| Can't delete Contact | Related records exist | Delete related Tasks/Events first |
| Encrypted field in WHERE | Shield encryption limitation | Use deterministic encryption or query differently |
| PII in logs | Missing redaction | Wrap all SF logging with redactSfRecord |
Resources
- Salesforce Data Protection & Privacy
- Individual Object
- Shield Platform Encryption
- GDPR Compliance in Salesforce
Next Steps
For enterprise access control, see
salesforce-enterprise-rbac.