[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6F9RW80NGNF5MMDN4RT6AY8":3,"skill-same:01M6F9RW80NGNF5MMDN4RT6AY8":88},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":31,"publishedAt":52,"linkOnly":53,"markdownContent":54,"markdownBody":55,"frontMatter":56,"refName":65,"commitSha":66,"skillDirectory":67,"forksCount":68,"repositoryHtmlUrl":69,"repositoryHomepageUrl":70,"ownerHtmlUrl":71,"ownerBlogUrl":6,"ownerDescription":72,"updatedAt":73,"install":74,"resources":87},"01M6F9RW80NGNF5MMDN4RT6AY8","deepgram-data-handling",null,"Implement audio data handling best practices for Deepgram integrations.\nUse when managing audio file storage, implementing data retention,\nor ensuring GDPR\u002FHIPAA compliance for transcription data.\nTrigger: \"deepgram data\", \"audio storage\", \"transcription data\",\n\"deepgram GDPR\", \"deepgram HIPAA\", \"deepgram privacy\", \"PII redaction\".","ComeOnOliver\u002Fskillshub","ComeOnOliver","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F43215937?v=4","01M6E5JNFECJAAVFE0W7SMWWD2","Haoran Shu","01M6E5JNNDQS7AJZDYFQ8TPZCK",66,"MIT","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fdeepgram-data-handling\u002FSKILL.md",[18,23,28],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000016","图像与多媒体","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000033","数据分析师","PROFESSION","适用职业",{"categoryNo":29,"categoryName":30,"taxonomyType":26,"taxonomyTypeDesc":27},"01JBSEEDCAT000000000000037","律师与法务",[32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51],"deepgram data handling","deepgram","data","integrations","retention","trigger","io","use","edit","write","read","openclaw","Bash","Audio","pii","saas","best practices","code","storage","gcloud","2026-11-10 10:12:30",false,"---\nname: deepgram-data-handling\ndescription: |\n  Implement audio data handling best practices for Deepgram integrations.\n  Use when managing audio file storage, implementing data retention,\n  or ensuring GDPR\u002FHIPAA compliance for transcription data.\n  Trigger: \"deepgram data\", \"audio storage\", \"transcription data\",\n  \"deepgram GDPR\", \"deepgram HIPAA\", \"deepgram privacy\", \"PII redaction\".\nallowed-tools: Read, Write, Edit, Bash(aws:*), Bash(gcloud:*)\nversion: 1.0.0\nlicense: MIT\nauthor: Jeremy Longshore \u003Cjeremy@intentsolutions.io>\ncompatible-with: claude-code, codex, openclaw\ntags: [saas, deepgram, data, compliance, privacy]\n\n---\n# Deepgram Data Handling\n\n## Overview\nBest practices for handling audio and transcript data with Deepgram. Covers Deepgram's built-in `redact` parameter for PII, secure audio upload with encryption, transcript storage patterns, data retention policies, and GDPR\u002FHIPAA compliance workflows.\n\n## Data Privacy Quick Reference\n\n| Deepgram Feature | What It Does | Enable |\n|-------------------|-------------|--------|\n| `redact: ['pci']` | Masks credit card numbers in transcript | Query param |\n| `redact: ['ssn']` | Masks Social Security numbers | Query param |\n| `redact: ['numbers']` | Masks all numeric sequences | Query param |\n| Data retention | Deepgram does NOT store audio or transcripts | Default behavior |\n\n**Deepgram's data policy:** Audio is processed in real-time and not stored. Transcripts are not retained unless you use Deepgram's optional storage features.\n\n## Instructions\n\n### Step 1: Deepgram Built-in PII Redaction\n\n```typescript\nimport { createClient } from '@deepgram\u002Fsdk';\n\nconst deepgram = createClient(process.env.DEEPGRAM_API_KEY!);\n\n\u002F\u002F Deepgram redacts PII directly during transcription\nconst { result } = await deepgram.listen.prerecorded.transcribeUrl(\n  { url: audioUrl },\n  {\n    model: 'nova-3',\n    smart_format: true,\n    redact: ['pci', 'ssn'],  \u002F\u002F Credit cards + SSNs -> [REDACTED]\n  }\n);\n\n\u002F\u002F Output: \"My card is [REDACTED] and SSN is [REDACTED]\"\nconsole.log(result.results.channels[0].alternatives[0].transcript);\n\n\u002F\u002F For maximum privacy, redact all numbers:\n\u002F\u002F redact: ['pci', 'ssn', 'numbers']\n```\n\n### Step 2: Application-Level PII Redaction\n\n```typescript\n\u002F\u002F Additional redaction patterns beyond Deepgram's built-in\nconst piiPatterns: Array\u003C{ name: string; pattern: RegExp; replacement: string }> = [\n  { name: 'email',    pattern: \u002F\\b[\\w.-]+@[\\w.-]+\\.\\w{2,}\\b\u002Fg, replacement: '[EMAIL]' },\n  { name: 'phone',    pattern: \u002F\\b(\\+?\\d{1,3}[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}\\b\u002Fg, replacement: '[PHONE]' },\n  { name: 'dob',      pattern: \u002F\\b(0[1-9]|1[0-2])[\\\u002F.-](0[1-9]|[12]\\d|3[01])[\\\u002F.-](19|20)\\d{2}\\b\u002Fg, replacement: '[DOB]' },\n  { name: 'address',  pattern: \u002F\\b\\d{1,5}\\s[\\w\\s]+(?:Street|St|Avenue|Ave|Road|Rd|Drive|Dr|Lane|Ln|Boulevard|Blvd)\\b\u002Fgi, replacement: '[ADDRESS]' },\n];\n\nfunction redactPII(text: string): { redacted: string; found: string[] } {\n  let redacted = text;\n  const found: string[] = [];\n\n  for (const { name, pattern, replacement } of piiPatterns) {\n    const matches = text.match(pattern);\n    if (matches) {\n      found.push(`${name}: ${matches.length} occurrence(s)`);\n      redacted = redacted.replace(pattern, replacement);\n    }\n  }\n\n  return { redacted, found };\n}\n\n\u002F\u002F Usage after Deepgram transcription:\nconst transcript = result.results.channels[0].alternatives[0].transcript;\nconst { redacted, found } = redactPII(transcript);\nif (found.length > 0) console.log('PII found and redacted:', found);\n```\n\n### Step 3: Secure Audio Upload and Storage\n\n```typescript\nimport { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk\u002Fclient-s3';\nimport { getSignedUrl } from '@aws-sdk\u002Fs3-request-presigner';\nimport { createHash, randomUUID } from 'crypto';\nimport { readFileSync } from 'fs';\n\nconst s3 = new S3Client({ region: process.env.AWS_REGION ?? 'us-east-1' });\nconst BUCKET = process.env.AUDIO_BUCKET!;\n\nasync function uploadAudio(filePath: string, metadata: Record\u003Cstring, string> = {}) {\n  const audio = readFileSync(filePath);\n  const checksum = createHash('sha256').update(audio).digest('hex');\n  const key = `audio\u002F${randomUUID()}-${checksum.substring(0, 8)}.wav`;\n\n  await s3.send(new PutObjectCommand({\n    Bucket: BUCKET,\n    Key: key,\n    Body: audio,\n    ContentType: 'audio\u002Fwav',\n    ServerSideEncryption: 'aws:kms',  \u002F\u002F Encrypt at rest\n    Metadata: {\n      ...metadata,\n      checksum,\n      uploadedAt: new Date().toISOString(),\n    },\n  }));\n\n  \u002F\u002F Generate presigned URL for Deepgram to fetch (expires in 1 hour)\n  const presignedUrl = await getSignedUrl(s3,\n    new GetObjectCommand({ Bucket: BUCKET, Key: key }),\n    { expiresIn: 3600 }\n  );\n\n  return { key, checksum, presignedUrl };\n}\n\n\u002F\u002F Upload -> Get presigned URL -> Send to Deepgram\nconst { presignedUrl } = await uploadAudio('.\u002Frecording.wav', { source: 'call-center' });\nconst { result } = await deepgram.listen.prerecorded.transcribeUrl(\n  { url: presignedUrl },\n  { model: 'nova-3', smart_format: true, redact: ['pci', 'ssn'] }\n);\n```\n\n### Step 4: Transcript Storage Pattern\n\n```typescript\ninterface StoredTranscript {\n  id: string;\n  audioKey: string;           \u002F\u002F S3 reference\n  requestId: string;          \u002F\u002F Deepgram request_id\n  transcript: string;         \u002F\u002F Redacted text\n  confidence: number;\n  duration: number;           \u002F\u002F Audio duration in seconds\n  model: string;\n  speakers: number;\n  utterances?: Array\u003C{\n    speaker: number;\n    text: string;\n    start: number;\n    end: number;\n  }>;\n  metadata: {\n    redacted: boolean;\n    piiTypesFound: string[];\n    createdAt: string;\n    retentionPolicy: 'standard' | 'legal_hold' | 'hipaa';\n    expiresAt: string;\n  };\n}\n\nfunction buildTranscriptRecord(\n  audioKey: string,\n  result: any,\n  retentionDays = 90\n): StoredTranscript {\n  const alt = result.results.channels[0].alternatives[0];\n  const { redacted, found } = redactPII(alt.transcript);\n\n  return {\n    id: randomUUID(),\n    audioKey,\n    requestId: result.metadata.request_id,\n    transcript: redacted,\n    confidence: alt.confidence,\n    duration: result.metadata.duration,\n    model: Object.keys(result.metadata.model_info ?? {})[0] ?? 'unknown',\n    speakers: new Set(alt.words?.map((w: any) => w.speaker).filter(Boolean)).size,\n    utterances: result.results.utterances?.map((u: any) => ({\n      speaker: u.speaker,\n      text: u.transcript,\n      start: u.start,\n      end: u.end,\n    })),\n    metadata: {\n      redacted: found.length > 0,\n      piiTypesFound: found,\n      createdAt: new Date().toISOString(),\n      retentionPolicy: 'standard',\n      expiresAt: new Date(Date.now() + retentionDays * 86400000).toISOString(),\n    },\n  };\n}\n```\n\n### Step 5: Data Retention Policies\n\n```typescript\nconst retentionPolicies = {\n  standard: { days: 90, description: 'Default retention' },\n  legal_hold: { days: 2555, description: '7 years for legal' },\n  hipaa: { days: 2190, description: '6 years per HIPAA' },\n  temp: { days: 7, description: 'Temporary processing' },\n};\n\nasync function enforceRetention(db: any, s3Client: S3Client, bucket: string) {\n  const now = new Date();\n\n  \u002F\u002F Find expired transcripts\n  const expired = await db.query(\n    'SELECT id, audio_key FROM transcripts WHERE expires_at \u003C $1 AND retention_policy != $2',\n    [now.toISOString(), 'legal_hold']\n  );\n\n  console.log(`Found ${expired.rows.length} expired transcripts`);\n\n  for (const row of expired.rows) {\n    \u002F\u002F Delete audio from S3\n    try {\n      await s3Client.send(new DeleteObjectCommand({\n        Bucket: bucket, Key: row.audio_key,\n      }));\n    } catch (err: any) {\n      console.error(`S3 delete failed for ${row.audio_key}:`, err.message);\n    }\n\n    \u002F\u002F Delete transcript from database\n    await db.query('DELETE FROM transcripts WHERE id = $1', [row.id]);\n    console.log(`Deleted: ${row.id}`);\n  }\n\n  return expired.rows.length;\n}\n```\n\n### Step 6: GDPR Right to Erasure\n\n```typescript\nasync function processErasureRequest(userId: string, db: any, s3Client: S3Client, bucket: string) {\n  console.log(`Processing GDPR erasure request for user: ${userId}`);\n\n  \u002F\u002F 1. Find all user transcripts\n  const transcripts = await db.query(\n    'SELECT id, audio_key FROM transcripts WHERE user_id = $1', [userId]\n  );\n\n  \u002F\u002F 2. Delete audio files from S3\n  for (const row of transcripts.rows) {\n    if (row.audio_key) {\n      await s3Client.send(new DeleteObjectCommand({ Bucket: bucket, Key: row.audio_key }));\n    }\n  }\n\n  \u002F\u002F 3. Delete transcripts from database\n  const deleted = await db.query('DELETE FROM transcripts WHERE user_id = $1', [userId]);\n\n  \u002F\u002F 4. Delete user metadata\n  await db.query('DELETE FROM user_metadata WHERE user_id = $1', [userId]);\n\n  \u002F\u002F 5. Audit log (keep for compliance — does not contain PII)\n  console.log(JSON.stringify({\n    action: 'gdpr_erasure',\n    userId: userId.substring(0, 8) + '...',  \u002F\u002F Partial for audit\n    transcriptsDeleted: deleted.rowCount,\n    audioFilesDeleted: transcripts.rows.length,\n    timestamp: new Date().toISOString(),\n  }));\n\n  return { transcriptsDeleted: deleted.rowCount, audioFilesDeleted: transcripts.rows.length };\n}\n```\n\n## Output\n- Deepgram built-in PII redaction (pci, ssn, numbers)\n- Application-level PII redaction (email, phone, DOB, address)\n- Secure audio upload to S3 with KMS encryption\n- Transcript storage pattern with retention metadata\n- Automated retention enforcement\n- GDPR erasure workflow\n\n## Error Handling\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| PII still visible | Deepgram `redact` not set | Add `redact: ['pci', 'ssn']` to options |\n| S3 upload fails | Missing KMS permissions | Add `kms:GenerateDataKey` to IAM role |\n| Retention not enforced | Cron not running | Schedule retention job, add monitoring |\n| Erasure incomplete | Transaction failed | Use database transactions for atomic delete |\n\n## Resources\n- [Deepgram Redaction](https:\u002F\u002Fdevelopers.deepgram.com\u002Fdocs\u002Fredaction)\n- [Deepgram Security](https:\u002F\u002Fdeepgram.com\u002Fsecurity)\n- [HIPAA Compliance](https:\u002F\u002Fdeepgram.com\u002Fhipaa)\n- [GDPR Guide](https:\u002F\u002Fdevelopers.deepgram.com\u002Fdocs\u002Fgdpr)\n\n","# Deepgram Data Handling\n\n## Overview\nBest practices for handling audio and transcript data with Deepgram. Covers Deepgram's built-in `redact` parameter for PII, secure audio upload with encryption, transcript storage patterns, data retention policies, and GDPR\u002FHIPAA compliance workflows.\n\n## Data Privacy Quick Reference\n\n| Deepgram Feature | What It Does | Enable |\n|-------------------|-------------|--------|\n| `redact: ['pci']` | Masks credit card numbers in transcript | Query param |\n| `redact: ['ssn']` | Masks Social Security numbers | Query param |\n| `redact: ['numbers']` | Masks all numeric sequences | Query param |\n| Data retention | Deepgram does NOT store audio or transcripts | Default behavior |\n\n**Deepgram's data policy:** Audio is processed in real-time and not stored. Transcripts are not retained unless you use Deepgram's optional storage features.\n\n## Instructions\n\n### Step 1: Deepgram Built-in PII Redaction\n\n```typescript\nimport { createClient } from '@deepgram\u002Fsdk';\n\nconst deepgram = createClient(process.env.DEEPGRAM_API_KEY!);\n\n\u002F\u002F Deepgram redacts PII directly during transcription\nconst { result } = await deepgram.listen.prerecorded.transcribeUrl(\n  { url: audioUrl },\n  {\n    model: 'nova-3',\n    smart_format: true,\n    redact: ['pci', 'ssn'],  \u002F\u002F Credit cards + SSNs -> [REDACTED]\n  }\n);\n\n\u002F\u002F Output: \"My card is [REDACTED] and SSN is [REDACTED]\"\nconsole.log(result.results.channels[0].alternatives[0].transcript);\n\n\u002F\u002F For maximum privacy, redact all numbers:\n\u002F\u002F redact: ['pci', 'ssn', 'numbers']\n```\n\n### Step 2: Application-Level PII Redaction\n\n```typescript\n\u002F\u002F Additional redaction patterns beyond Deepgram's built-in\nconst piiPatterns: Array\u003C{ name: string; pattern: RegExp; replacement: string }> = [\n  { name: 'email',    pattern: \u002F\\b[\\w.-]+@[\\w.-]+\\.\\w{2,}\\b\u002Fg, replacement: '[EMAIL]' },\n  { name: 'phone',    pattern: \u002F\\b(\\+?\\d{1,3}[-.\\s]?)?\\(?\\d{3}\\)?[-.\\s]?\\d{3}[-.\\s]?\\d{4}\\b\u002Fg, replacement: '[PHONE]' },\n  { name: 'dob',      pattern: \u002F\\b(0[1-9]|1[0-2])[\\\u002F.-](0[1-9]|[12]\\d|3[01])[\\\u002F.-](19|20)\\d{2}\\b\u002Fg, replacement: '[DOB]' },\n  { name: 'address',  pattern: \u002F\\b\\d{1,5}\\s[\\w\\s]+(?:Street|St|Avenue|Ave|Road|Rd|Drive|Dr|Lane|Ln|Boulevard|Blvd)\\b\u002Fgi, replacement: '[ADDRESS]' },\n];\n\nfunction redactPII(text: string): { redacted: string; found: string[] } {\n  let redacted = text;\n  const found: string[] = [];\n\n  for (const { name, pattern, replacement } of piiPatterns) {\n    const matches = text.match(pattern);\n    if (matches) {\n      found.push(`${name}: ${matches.length} occurrence(s)`);\n      redacted = redacted.replace(pattern, replacement);\n    }\n  }\n\n  return { redacted, found };\n}\n\n\u002F\u002F Usage after Deepgram transcription:\nconst transcript = result.results.channels[0].alternatives[0].transcript;\nconst { redacted, found } = redactPII(transcript);\nif (found.length > 0) console.log('PII found and redacted:', found);\n```\n\n### Step 3: Secure Audio Upload and Storage\n\n```typescript\nimport { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk\u002Fclient-s3';\nimport { getSignedUrl } from '@aws-sdk\u002Fs3-request-presigner';\nimport { createHash, randomUUID } from 'crypto';\nimport { readFileSync } from 'fs';\n\nconst s3 = new S3Client({ region: process.env.AWS_REGION ?? 'us-east-1' });\nconst BUCKET = process.env.AUDIO_BUCKET!;\n\nasync function uploadAudio(filePath: string, metadata: Record\u003Cstring, string> = {}) {\n  const audio = readFileSync(filePath);\n  const checksum = createHash('sha256').update(audio).digest('hex');\n  const key = `audio\u002F${randomUUID()}-${checksum.substring(0, 8)}.wav`;\n\n  await s3.send(new PutObjectCommand({\n    Bucket: BUCKET,\n    Key: key,\n    Body: audio,\n    ContentType: 'audio\u002Fwav',\n    ServerSideEncryption: 'aws:kms',  \u002F\u002F Encrypt at rest\n    Metadata: {\n      ...metadata,\n      checksum,\n      uploadedAt: new Date().toISOString(),\n    },\n  }));\n\n  \u002F\u002F Generate presigned URL for Deepgram to fetch (expires in 1 hour)\n  const presignedUrl = await getSignedUrl(s3,\n    new GetObjectCommand({ Bucket: BUCKET, Key: key }),\n    { expiresIn: 3600 }\n  );\n\n  return { key, checksum, presignedUrl };\n}\n\n\u002F\u002F Upload -> Get presigned URL -> Send to Deepgram\nconst { presignedUrl } = await uploadAudio('.\u002Frecording.wav', { source: 'call-center' });\nconst { result } = await deepgram.listen.prerecorded.transcribeUrl(\n  { url: presignedUrl },\n  { model: 'nova-3', smart_format: true, redact: ['pci', 'ssn'] }\n);\n```\n\n### Step 4: Transcript Storage Pattern\n\n```typescript\ninterface StoredTranscript {\n  id: string;\n  audioKey: string;           \u002F\u002F S3 reference\n  requestId: string;          \u002F\u002F Deepgram request_id\n  transcript: string;         \u002F\u002F Redacted text\n  confidence: number;\n  duration: number;           \u002F\u002F Audio duration in seconds\n  model: string;\n  speakers: number;\n  utterances?: Array\u003C{\n    speaker: number;\n    text: string;\n    start: number;\n    end: number;\n  }>;\n  metadata: {\n    redacted: boolean;\n    piiTypesFound: string[];\n    createdAt: string;\n    retentionPolicy: 'standard' | 'legal_hold' | 'hipaa';\n    expiresAt: string;\n  };\n}\n\nfunction buildTranscriptRecord(\n  audioKey: string,\n  result: any,\n  retentionDays = 90\n): StoredTranscript {\n  const alt = result.results.channels[0].alternatives[0];\n  const { redacted, found } = redactPII(alt.transcript);\n\n  return {\n    id: randomUUID(),\n    audioKey,\n    requestId: result.metadata.request_id,\n    transcript: redacted,\n    confidence: alt.confidence,\n    duration: result.metadata.duration,\n    model: Object.keys(result.metadata.model_info ?? {})[0] ?? 'unknown',\n    speakers: new Set(alt.words?.map((w: any) => w.speaker).filter(Boolean)).size,\n    utterances: result.results.utterances?.map((u: any) => ({\n      speaker: u.speaker,\n      text: u.transcript,\n      start: u.start,\n      end: u.end,\n    })),\n    metadata: {\n      redacted: found.length > 0,\n      piiTypesFound: found,\n      createdAt: new Date().toISOString(),\n      retentionPolicy: 'standard',\n      expiresAt: new Date(Date.now() + retentionDays * 86400000).toISOString(),\n    },\n  };\n}\n```\n\n### Step 5: Data Retention Policies\n\n```typescript\nconst retentionPolicies = {\n  standard: { days: 90, description: 'Default retention' },\n  legal_hold: { days: 2555, description: '7 years for legal' },\n  hipaa: { days: 2190, description: '6 years per HIPAA' },\n  temp: { days: 7, description: 'Temporary processing' },\n};\n\nasync function enforceRetention(db: any, s3Client: S3Client, bucket: string) {\n  const now = new Date();\n\n  \u002F\u002F Find expired transcripts\n  const expired = await db.query(\n    'SELECT id, audio_key FROM transcripts WHERE expires_at \u003C $1 AND retention_policy != $2',\n    [now.toISOString(), 'legal_hold']\n  );\n\n  console.log(`Found ${expired.rows.length} expired transcripts`);\n\n  for (const row of expired.rows) {\n    \u002F\u002F Delete audio from S3\n    try {\n      await s3Client.send(new DeleteObjectCommand({\n        Bucket: bucket, Key: row.audio_key,\n      }));\n    } catch (err: any) {\n      console.error(`S3 delete failed for ${row.audio_key}:`, err.message);\n    }\n\n    \u002F\u002F Delete transcript from database\n    await db.query('DELETE FROM transcripts WHERE id = $1', [row.id]);\n    console.log(`Deleted: ${row.id}`);\n  }\n\n  return expired.rows.length;\n}\n```\n\n### Step 6: GDPR Right to Erasure\n\n```typescript\nasync function processErasureRequest(userId: string, db: any, s3Client: S3Client, bucket: string) {\n  console.log(`Processing GDPR erasure request for user: ${userId}`);\n\n  \u002F\u002F 1. Find all user transcripts\n  const transcripts = await db.query(\n    'SELECT id, audio_key FROM transcripts WHERE user_id = $1', [userId]\n  );\n\n  \u002F\u002F 2. Delete audio files from S3\n  for (const row of transcripts.rows) {\n    if (row.audio_key) {\n      await s3Client.send(new DeleteObjectCommand({ Bucket: bucket, Key: row.audio_key }));\n    }\n  }\n\n  \u002F\u002F 3. Delete transcripts from database\n  const deleted = await db.query('DELETE FROM transcripts WHERE user_id = $1', [userId]);\n\n  \u002F\u002F 4. Delete user metadata\n  await db.query('DELETE FROM user_metadata WHERE user_id = $1', [userId]);\n\n  \u002F\u002F 5. Audit log (keep for compliance — does not contain PII)\n  console.log(JSON.stringify({\n    action: 'gdpr_erasure',\n    userId: userId.substring(0, 8) + '...',  \u002F\u002F Partial for audit\n    transcriptsDeleted: deleted.rowCount,\n    audioFilesDeleted: transcripts.rows.length,\n    timestamp: new Date().toISOString(),\n  }));\n\n  return { transcriptsDeleted: deleted.rowCount, audioFilesDeleted: transcripts.rows.length };\n}\n```\n\n## Output\n- Deepgram built-in PII redaction (pci, ssn, numbers)\n- Application-level PII redaction (email, phone, DOB, address)\n- Secure audio upload to S3 with KMS encryption\n- Transcript storage pattern with retention metadata\n- Automated retention enforcement\n- GDPR erasure workflow\n\n## Error Handling\n| Issue | Cause | Solution |\n|-------|-------|----------|\n| PII still visible | Deepgram `redact` not set | Add `redact: ['pci', 'ssn']` to options |\n| S3 upload fails | Missing KMS permissions | Add `kms:GenerateDataKey` to IAM role |\n| Retention not enforced | Cron not running | Schedule retention job, add monitoring |\n| Erasure incomplete | Transaction failed | Use database transactions for atomic delete |\n\n## Resources\n- [Deepgram Redaction](https:\u002F\u002Fdevelopers.deepgram.com\u002Fdocs\u002Fredaction)\n- [Deepgram Security](https:\u002F\u002Fdeepgram.com\u002Fsecurity)\n- [HIPAA Compliance](https:\u002F\u002Fdeepgram.com\u002Fhipaa)\n- [GDPR Guide](https:\u002F\u002Fdevelopers.deepgram.com\u002Fdocs\u002Fgdpr)\n\n",{"name":5,"tags":57,"author":60,"license":15,"version":61,"description":62,"allowed-tools":63,"compatible-with":64},[47,33,34,58,59],"compliance","privacy","Jeremy Longshore \u003Cjeremy@intentsolutions.io>","1.0.0","Implement audio data handling best practices for Deepgram integrations.\nUse when managing audio file storage, implementing data retention,\nor ensuring GDPR\u002FHIPAA compliance for transcription data.\nTrigger: \"deepgram data\", \"audio storage\", \"transcription data\",\n\"deepgram GDPR\", \"deepgram HIPAA\", \"deepgram privacy\", \"PII redaction\".\n","Read, Write, Edit, Bash(aws:*), Bash(gcloud:*)","claude-code, codex, openclaw","main","def8531e65114c0fca8fb8551c1871ee0eed705c","skills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fdeepgram-data-handling",24,"https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub","https:\u002F\u002Fskillshub.wtf","https:\u002F\u002Fgithub.com\u002FComeOnOliver","AI & Blockchain Engineer\r\n","2026-06-24 22:07:19",{"source":8,"skillName":5,"commands":75,"prompt":85,"zipAvailable":86},[76,79,82],{"tool":77,"command":78},"npx","npx skills add ComeOnOliver\u002Fskillshub --skill deepgram-data-handling",{"tool":80,"command":81},"bunx","bunx skills add ComeOnOliver\u002Fskillshub --skill deepgram-data-handling",{"tool":83,"command":84},"pnpm","pnpm dlx skills add ComeOnOliver\u002Fskillshub --skill deepgram-data-handling","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fjeremylongshore\u002Fclaude-code-plugins-plus-skills\u002Fdeepgram-data-handling\u002FSKILL.md",true,[],[89,101,111,120,126,133],{"skillNo":90,"name":91,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":92,"categories":93,"keywords":97,"publishedAt":52},"01M6FKJN13GMG4KY57J3QD8GY5","model-hierarchy-skill","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzscole\u002Fmodel-hierarchy-skill\u002Fmodel-hierarchy-skill\u002FSKILL.md",[94],{"categoryNo":95,"categoryName":96,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[98,99,100],"model","model hierarchy","model hierarchy skill",{"skillNo":102,"name":103,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":104,"categories":105,"keywords":107,"publishedAt":52},"01M6FKJJJ6GCAMR4PPPRD12M5X","zoom-mcp","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-mcp\u002FSKILL.md",[106],{"categoryNo":95,"categoryName":96,"taxonomyType":21,"taxonomyTypeDesc":22},[108,109,110],"MCP","zoom","zoom mcp",{"skillNo":112,"name":113,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":114,"categories":115,"keywords":116,"publishedAt":52},"01M6FKJE3KYT3KPEZMEEHYKA6K","zoom-apps-sdk","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fzoom-apps-sdk\u002FSKILL.md",[],[117,118,119,109],"sdk","zoom apps sdk","apps",{"skillNo":121,"name":122,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":123,"categories":124,"keywords":125,"publishedAt":52},"01M6FKJ9EDH9Q5VWDF8HAJRSP0","windows","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwindows\u002FSKILL.md",[],[122],{"skillNo":127,"name":128,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":129,"categories":130,"keywords":132,"publishedAt":52},"01M6FKJ666BEEFC3AE9GJ72Q93","whiteboard","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwhiteboard\u002FSKILL.md",[131],{"categoryNo":95,"categoryName":96,"taxonomyType":21,"taxonomyTypeDesc":22},[128],{"skillNo":134,"name":135,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":136,"categories":137,"keywords":138,"publishedAt":52},"01M6FKJ21WFCDGTJQ2Q91T9DVW","websockets","https:\u002F\u002Fgithub.com\u002FComeOnOliver\u002Fskillshub\u002Fblob\u002Fmain\u002Fskills\u002Fzoom\u002Fskills\u002Fwebsockets\u002FSKILL.md",[],[135]]