CtrlK
BlogDocsLog inGet started
Tessl Logo

gamma-data-handling

Handle data privacy, retention, and compliance for Gamma integrations. Use when implementing GDPR compliance, data retention policies, or managing user data within Gamma workflows. Trigger with phrases like "gamma data", "gamma privacy", "gamma GDPR", "gamma data retention", "gamma compliance".

74

Quality

70%

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Passed

No known issues

Optimize this skill with Tessl

npx tessl skill review --optimize ./plugins/saas-packs/gamma-pack/skills/gamma-data-handling/SKILL.md
SKILL.md
Quality
Evals
Security

Gamma Data Handling

Overview

Data handling, privacy controls, and compliance for Gamma API integrations. Gamma processes user-submitted content through AI to generate presentations -- understand what data flows where and how to handle PII, retention, and GDPR requirements.

Prerequisites

  • Understanding of data privacy regulations (GDPR, CCPA)
  • Completed gamma-install-auth setup
  • Data classification policies defined

Data Flow Map

User Input (content, prompts)
     │
     ▼
┌──────────────┐
│  Your App    │  ← PII may be in content (names, company data)
│  (API key)   │
└──────┬───────┘
       │ POST /v1.0/generations
       ▼
┌──────────────┐
│  Gamma API   │  ← Content processed by AI
│  (gamma.app) │  ← Images generated
└──────┬───────┘
       │ gammaUrl + exportUrl
       ▼
┌──────────────┐
│  Generated   │  ← Presentation stored in Gamma workspace
│  Content     │  ← Export files (PDF/PPTX/PNG) temporary
└──────────────┘

Data Classification

Data TypeClassificationWhere StoredRetention
API keySecretYour env varsActive use only
Content/promptsMay contain PIIGamma servers (during generation)Gamma's policy
Generated gammasUser dataGamma workspaceUser-controlled
Export files (PDF/PPTX)User dataTemporary URLsDownload promptly, URLs expire
User prompts in logsPII riskYour infrastructureYour policy (sanitize!)
Credit usageBilling dataGammaPer Gamma ToS

Instructions

Step 1: Sanitize Content Before Sending

// src/gamma/sanitize.ts
// Remove PII from content before sending to Gamma if not needed

interface SanitizeOptions {
  removeEmails: boolean;
  removePhones: boolean;
  maskNames: boolean;
}

function sanitizeContent(content: string, opts: SanitizeOptions): string {
  let sanitized = content;

  if (opts.removeEmails) {
    sanitized = sanitized.replace(/[\w.-]+@[\w.-]+\.\w+/g, "[email]");
  }
  if (opts.removePhones) {
    sanitized = sanitized.replace(/\+?[\d\s()-]{10,}/g, "[phone]");
  }
  if (opts.maskNames) {
    // Only mask if you have a list of known names
    // Generic regex would be too aggressive
  }

  return sanitized;
}

// Usage: sanitize before generation
const safeContent = sanitizeContent(userContent, {
  removeEmails: true,
  removePhones: true,
  maskNames: false,
});

await gamma.generate({
  content: safeContent,
  outputFormat: "presentation",
});

Step 2: Sanitize Logs

// src/gamma/logging.ts
// Never log raw content or API keys

function logGeneration(request: any, result: any) {
  console.log(JSON.stringify({
    event: "gamma_generation",
    timestamp: new Date().toISOString(),
    generationId: result.generationId,
    outputFormat: request.outputFormat,
    contentLength: request.content?.length,
    // NEVER log: content (may have PII), apiKey
    status: result.status,
    creditsUsed: result.creditsUsed,
  }));
}

Step 3: Export File Handling

// src/gamma/exports.ts
// Export URLs are temporary — download and store securely

import { writeFile } from "node:fs/promises";
import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";

async function archiveExport(
  exportUrl: string,
  metadata: { generationId: string; userId: string }
) {
  // Download immediately — URLs expire
  const res = await fetch(exportUrl);
  if (!res.ok) throw new Error(`Export download failed: ${res.status}`);
  const buffer = Buffer.from(await res.arrayBuffer());

  // Store with encryption
  const s3 = new S3Client({ region: "us-east-1" });
  const key = `gamma-exports/${metadata.userId}/${metadata.generationId}.pdf`;

  await s3.send(new PutObjectCommand({
    Bucket: process.env.EXPORTS_BUCKET!,
    Key: key,
    Body: buffer,
    ContentType: "application/pdf",
    ServerSideEncryption: "aws:kms",
    Metadata: {
      generationId: metadata.generationId,
      archivedAt: new Date().toISOString(),
    },
  }));

  console.log(`Archived: s3://${process.env.EXPORTS_BUCKET}/${key}`);
}

Step 4: Data Retention Policy

// src/gamma/retention.ts
interface RetentionPolicy {
  exportMaxDays: number;     // Delete local export copies
  logRetentionDays: number;  // Anonymize generation logs
  promptRetentionDays: number; // Delete stored prompts
}

const POLICY: RetentionPolicy = {
  exportMaxDays: 90,       // Keep exports 90 days
  logRetentionDays: 30,    // Anonymize logs after 30 days
  promptRetentionDays: 7,  // Delete prompts after 7 days
};

async function enforceRetention() {
  const cutoff = new Date();

  // Delete old exports from S3
  cutoff.setDate(cutoff.getDate() - POLICY.exportMaxDays);
  await deleteOldExports(cutoff);

  // Anonymize old logs
  cutoff.setDate(cutoff.getDate() + POLICY.exportMaxDays - POLICY.logRetentionDays);
  await anonymizeLogs(cutoff);

  // Delete stored prompts
  cutoff.setDate(cutoff.getDate() + POLICY.logRetentionDays - POLICY.promptRetentionDays);
  await deletePrompts(cutoff);
}

Step 5: GDPR Request Handling

// Handle data subject access/erasure requests
async function handleGdprRequest(
  type: "access" | "erasure",
  userId: string
) {
  if (type === "access") {
    // Return all data we store about this user
    return {
      generations: await db.generations.findMany({ where: { userId } }),
      exports: await listS3Objects(`gamma-exports/${userId}/`),
      // Note: data stored IN Gamma's workspace is Gamma's responsibility
      // Direct user to gamma.app to access/delete their workspace data
    };
  }

  if (type === "erasure") {
    // Delete from our systems
    await db.generations.deleteMany({ where: { userId } });
    await deleteS3Prefix(`gamma-exports/${userId}/`);
    // Instruct user to delete Gamma workspace data at gamma.app
    return { deleted: true, note: "Delete Gamma workspace data at gamma.app" };
  }
}

Compliance Checklist

  • Content sanitized before sending to Gamma API (PII removed if not needed)
  • API keys never logged
  • Export URLs downloaded promptly and stored encrypted
  • Retention policies defined and enforced
  • GDPR access/erasure request process documented
  • User consent obtained for AI processing of their content
  • Gamma DPA signed (if required by your jurisdiction)
  • Logs sanitized (no raw content or PII)

Error Handling

ErrorCauseSolution
Export URL expiredDownloaded too lateDownload immediately on generation completion
PII in logsMissing sanitizationAdd log sanitization middleware
Retention job failedScheduler stoppedMonitor cron job health
GDPR request incompleteGamma workspace not addressedDirect user to gamma.app for workspace data

Resources

  • Gamma Privacy Policy
  • Gamma Terms of Service
  • GDPR Compliance Guide

Next Steps

Proceed to gamma-enterprise-rbac for access control.

Repository
jeremylongshore/claude-code-plugins-plus-skills
Last updated
Created

Is this your skill?

If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.