
Gdpr Data Handling
Implement GDPR-aligned consent records, audit trails, and data-handling patterns before shipping EU-facing SaaS or APIs.
Overview
GDPR Data Handling is an agent skill most often used in Ship (also Build backend integrations, Operate ongoing compliance) that templates consent storage, audit logs, and change events for EU privacy obligations.
Install
npx skills add https://github.com/wshobson/agents --skill gdpr-data-handlingWhat is this skill?
- Documented consent schema with purpose, version, IP, and user-agent proof fields
- ConsentManager service pattern with upsert storage and auditLog entries for grant and withdraw
- Event emission (consent.changed) for downstream analytics and marketing system sync
- Worked implementation patterns beyond a checklist—ready to adapt to your datastore
- Aligns marketing, analytics, and product features to lawful basis and withdrawal flows
Adoption & trust: 10.4k installs on skills.sh; 36.5k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
You are shipping a SaaS that stores personal data but lack a proven consent model, audit trail, and way to propagate withdrawals to marketing and analytics.
Who is it for?
Solo builders launching B2C or EU-facing products who need engineer-ready GDPR patterns before go-live.
Skip if: Teams that only need a static privacy policy page with no programmatic consent or data subject request handling.
When should I use this skill?
Building or hardening applications that process personal data and need GDPR-style consent recording, audit trails, and downstream consent change events.
What do I get? / Deliverables
You get adaptable consent and audit patterns plus event hooks so grants and withdrawals are provable and downstream systems can react consistently.
- Consent schema and ConsentManager-style service skeleton
- Audit log structure and consent.changed event integration points
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Compliance hardening belongs on the Ship shelf because it gates safe launch for products that process personal data. Security subphase captures privacy law, consent proof, and data lifecycle obligations—not generic backend CRUD.
Where it fits
Model consents and audit logs while building signup and preference APIs.
Verify consent proof fields and withdrawal events before enabling production traffic in the EU.
Extend handlers for access or erasure requests without breaking the existing audit chain.
How it compares
Implementation-pattern skill for consent code—not a one-click legal compliance certificate or hosted CMP product.
Common Questions / FAQ
Who is gdpr-data-handling for?
Indie and solo developers building SaaS, APIs, or ecommerce flows who must implement consent and auditability in application code with agent assistance.
When should I use gdpr-data-handling?
Use it during Build when designing user and consent models, during Ship before processing EU personal data in production, and during Operate when extending data subject rights or withdrawal propagation.
Is gdpr-data-handling safe to install?
Check the Security Audits panel on this Prism page; treat any generated compliance code as requiring legal review and your own security testing before production.
SKILL.md
READMESKILL.md - Gdpr Data Handling
# gdpr-data-handling — detailed worked examples ## Implementation Patterns ### Pattern 1: Consent Management ```javascript // Consent data model const consentSchema = { userId: String, consents: [ { purpose: String, // 'marketing', 'analytics', etc. granted: Boolean, timestamp: Date, source: String, // 'web_form', 'api', etc. version: String, // Privacy policy version ipAddress: String, // For proof userAgent: String, // For proof }, ], auditLog: [ { action: String, // 'granted', 'withdrawn', 'updated' purpose: String, timestamp: Date, source: String, }, ], }; // Consent service class ConsentManager { async recordConsent(userId, purpose, granted, metadata) { const consent = { purpose, granted, timestamp: new Date(), source: metadata.source, version: await this.getCurrentPolicyVersion(), ipAddress: metadata.ipAddress, userAgent: metadata.userAgent, }; // Store consent await this.db.consents.updateOne( { userId }, { $push: { consents: consent, auditLog: { action: granted ? "granted" : "withdrawn", purpose, timestamp: consent.timestamp, source: metadata.source, }, }, }, { upsert: true }, ); // Emit event for downstream systems await this.eventBus.emit("consent.changed", { userId, purpose, granted, timestamp: consent.timestamp, }); } async hasConsent(userId, purpose) { const record = await this.db.consents.findOne({ userId }); if (!record) return false; const latestConsent = record.consents .filter((c) => c.purpose === purpose) .sort((a, b) => b.timestamp - a.timestamp)[0]; return latestConsent?.granted === true; } async getConsentHistory(userId) { const record = await this.db.consents.findOne({ userId }); return record?.auditLog || []; } } ``` ```html <!-- GDPR-compliant consent UI --> <div class="consent-banner" role="dialog" aria-labelledby="consent-title"> <h2 id="consent-title">Cookie Preferences</h2> <p> We use cookies to improve your experience. Select your preferences below. </p> <form id="consent-form"> <!-- Necessary - always on, no consent needed --> <div class="consent-category"> <input type="checkbox" id="necessary" checked disabled /> <label for="necessary"> <strong>Necessary</strong> <span>Required for the website to function. Cannot be disabled.</span> </label> </div> <!-- Analytics - requires consent --> <div class="consent-category"> <input type="checkbox" id="analytics" name="analytics" /> <label for="analytics"> <strong>Analytics</strong> <span>Help us understand how you use our site.</span> </label> </div> <!-- Marketing - requires consent --> <div class="consent-category"> <input type="checkbox" id="marketing" name="marketing" /> <label for="marketing"> <strong>Marketing</strong> <span>Personalized ads based on your interests.</span> </label> </div> <div class="consent-actions"> <button type="button" id="accept-all">Accept All</button> <button type="button" id="reject-all">Reject All</button> <button type="submit">Save Preferences</button> </div> <p class="consent-links"> <a href="/privacy-policy">Privacy Policy</a> | <a href="/cookie-policy">Cookie Policy</a> </p> </form> </div> ``` ### Pattern 2: Data Subject Access Request (DSAR) ```python from datetime import datetime, timedelta from typing import Dict, List, Optional import json class DSARHandler: """Handle Data Subject Access Requests.""" RESPONSE_DEADLINE_DAYS = 30 EXTENSION_ALLOWED_DAYS = 60 # For complex requests def __init__(self, data_sources: List['DataSource']):