Skip to content

vt-c-compliance-checklist

GDPR, SOC2, and security compliance patterns for B2B SaaS applications. Activates when discussing data handling, privacy, audit logging, or compliance requirements.

Plugin: core-standards
Category: Security & Compliance
Command: /vt-c-compliance-checklist


Compliance Checklist

This skill provides technical implementation guidance for common B2B SaaS compliance requirements.

When This Skill Activates

  • Implementing user data handling
  • Building audit logging
  • Discussing data retention or deletion
  • Working on authentication/authorization
  • Security review or compliance audit

GDPR Technical Requirements

1. Right to Access (Data Export)

Users must be able to export all their personal data.

// API endpoint for data export
app.get('/api/user/data-export', async (req, res) => {
  const userId = req.user.id;

  const userData = {
    profile: await db.user.findUnique({ where: { id: userId } }),
    preferences: await db.preferences.findMany({ where: { userId } }),
    activityLog: await db.activityLog.findMany({ where: { userId } }),
    // Include ALL user data across all tables
  };

  // Return as downloadable JSON
  res.setHeader('Content-Disposition', 'attachment; filename=my-data.json');
  res.json(userData);
});

2. Right to Erasure (Data Deletion)

Users must be able to request deletion of their data.

// Soft delete with scheduled hard delete
async function deleteUserData(userId: string) {
  // 1. Soft delete user record
  await db.user.update({
    where: { id: userId },
    data: {
      deletedAt: new Date(),
      email: `deleted-${userId}@deleted.local`, // Anonymize
      name: 'Deleted User'
    }
  });

  // 2. Schedule hard delete after retention period
  await queue.add('hard-delete-user', { userId }, {
    delay: 30 * 24 * 60 * 60 * 1000 // 30 days
  });

  // 3. Audit log the deletion request
  await auditLog('user_deletion_requested', { userId });
}

3. Data Minimization

Only collect data that's necessary.

// ❌ OVER-COLLECTION
interface UserRegistration {
  email: string;
  password: string;
  dateOfBirth: Date;     // Not needed
  phoneNumber: string;   // Not needed
  address: string;       // Not needed
}

// ✅ MINIMAL COLLECTION
interface UserRegistration {
  email: string;
  password: string;
  // Only collect additional data when needed for features
}

Track consent for data processing.

interface ConsentRecord {
  userId: string;
  purpose: 'marketing' | 'analytics' | 'product_updates';
  granted: boolean;
  grantedAt: Date;
  ipAddress: string;
  userAgent: string;
}

// Always check consent before processing
async function sendMarketingEmail(userId: string) {
  const consent = await db.consent.findFirst({
    where: { userId, purpose: 'marketing', granted: true }
  });

  if (!consent) {
    throw new Error('Marketing consent not granted');
  }

  // Proceed with email
}

SOC 2 Technical Controls

1. Audit Logging

Log all security-relevant events.

interface AuditLogEntry {
  timestamp: Date;
  eventType: string;
  userId: string | null;
  tenantId: string;
  resourceType: string;
  resourceId: string;
  action: 'create' | 'read' | 'update' | 'delete';
  ipAddress: string;
  userAgent: string;
  outcome: 'success' | 'failure';
  metadata: Record<string, unknown>;
}

// Events that MUST be logged
const REQUIRED_AUDIT_EVENTS = [
  'user_login',
  'user_logout',
  'user_login_failed',
  'password_change',
  'permission_change',
  'data_export',
  'data_deletion',
  'admin_action',
  'api_key_created',
  'api_key_revoked',
  'settings_changed',
];

2. Access Control

Implement role-based access control.

// Define permissions
const PERMISSIONS = {
  'user:read': ['admin', 'manager', 'user'],
  'user:write': ['admin', 'manager'],
  'user:delete': ['admin'],
  'billing:read': ['admin', 'billing'],
  'billing:write': ['admin'],
} as const;

// Check permission before action
function requirePermission(permission: keyof typeof PERMISSIONS) {
  return (req: Request, res: Response, next: NextFunction) => {
    const userRole = req.user.role;
    if (!PERMISSIONS[permission].includes(userRole)) {
      auditLog('permission_denied', {
        userId: req.user.id,
        permission,
        outcome: 'failure'
      });
      return res.status(403).json({ error: 'Forbidden' });
    }
    next();
  };
}

3. Encryption

Encrypt sensitive data at rest and in transit.

// At-rest encryption for sensitive fields
import { createCipheriv, createDecipheriv, randomBytes } from 'crypto';

class EncryptedField {
  private key = Buffer.from(process.env.ENCRYPTION_KEY!, 'hex');

  encrypt(plaintext: string): string {
    const iv = randomBytes(16);
    const cipher = createCipheriv('aes-256-gcm', this.key, iv);
    const encrypted = Buffer.concat([
      cipher.update(plaintext, 'utf8'),
      cipher.final()
    ]);
    const authTag = cipher.getAuthTag();
    return Buffer.concat([iv, authTag, encrypted]).toString('base64');
  }

  decrypt(ciphertext: string): string {
    const data = Buffer.from(ciphertext, 'base64');
    const iv = data.subarray(0, 16);
    const authTag = data.subarray(16, 32);
    const encrypted = data.subarray(32);
    const decipher = createDecipheriv('aes-256-gcm', this.key, iv);
    decipher.setAuthTag(authTag);
    return decipher.update(encrypted) + decipher.final('utf8');
  }
}

// Use for PII storage
const encryptedSSN = encryptedField.encrypt(user.ssn);

4. Session Management

Secure session handling.

const SESSION_CONFIG = {
  // Maximum session duration
  maxAge: 8 * 60 * 60 * 1000, // 8 hours

  // Idle timeout
  idleTimeout: 30 * 60 * 1000, // 30 minutes

  // Require re-auth for sensitive actions
  sensitiveActionTimeout: 5 * 60 * 1000, // 5 minutes

  // Cookie settings
  cookie: {
    httpOnly: true,
    secure: process.env.NODE_ENV === 'production',
    sameSite: 'strict' as const,
  }
};

// Force re-auth for sensitive actions
async function requireRecentAuth(req: Request) {
  const lastAuth = req.session.lastAuthAt;
  const now = Date.now();

  if (now - lastAuth > SESSION_CONFIG.sensitiveActionTimeout) {
    throw new Error('Please re-authenticate for this action');
  }
}

Compliance Checklist

Before Launch

  • [ ] Data Inventory - Document all personal data collected
  • [ ] Privacy Policy - Published and linked from signup
  • [ ] Consent Mechanism - Users can grant/revoke consent
  • [ ] Data Export - Users can download their data
  • [ ] Data Deletion - Users can request deletion
  • [ ] Audit Logging - All security events logged
  • [ ] Access Control - RBAC implemented
  • [ ] Encryption - Sensitive data encrypted at rest
  • [ ] HTTPS Only - All traffic encrypted in transit
  • [ ] Session Security - Proper session management
  • [ ] Password Policy - Strong password requirements
  • [ ] MFA Support - Multi-factor auth available

Periodic Review

  • [ ] Review access logs for anomalies
  • [ ] Audit user permissions
  • [ ] Test data export functionality
  • [ ] Test data deletion functionality
  • [ ] Review and rotate encryption keys
  • [ ] Update dependencies for security patches
  • [ ] Conduct penetration testing
  • [ ] Review third-party integrations

Data Retention

Define and enforce retention periods:

const RETENTION_PERIODS = {
  // Active data
  user_data: 'until_deletion_requested',

  // Audit logs (compliance requirement)
  audit_logs: '7_years',

  // Session data
  sessions: '30_days',

  // Analytics (anonymized)
  analytics: '2_years',

  // Soft-deleted data
  deleted_users: '30_days',
};

// Scheduled job to enforce retention
async function enforceRetention() {
  // Delete expired audit logs
  const auditCutoff = subYears(new Date(), 7);
  await db.auditLog.deleteMany({
    where: { createdAt: { lt: auditCutoff } }
  });

  // Hard delete soft-deleted users
  const deletionCutoff = subDays(new Date(), 30);
  await db.user.deleteMany({
    where: { deletedAt: { lt: deletionCutoff } }
  });
}