GDPR para Desarrolladores de Software | Lo Que Realmente Necesitas Implementar
Una guía de GDPR enfocada en desarrolladores. Cubre los requisitos técnicos, patrones de manejo de datos y decisiones a nivel de código que necesitas tomar.
El GDPR está vigente desde 2018, pero la mayoría de guías para desarrolladores todavía se centran en la teoría legal. Esta guía es diferente. Cubre los requisitos técnicos, el código que necesitas escribir y las decisiones arquitectónicas que hacen que el cumplimiento sea práctico en lugar de doloroso.
Si tu software almacena, procesa o toca datos personales de personas en la UE, esto te aplica. No importa dónde esté basada tu empresa.
Resumen del GDPR para Desarrolladores
Olvídate de los 99 artículos. Esto es lo que el GDPR significa para tu código:
- Recoge solo lo que necesitas. No almacenes datos “por si acaso.”
- Informa a los usuarios de lo que haces con sus datos. Y obtén su permiso cuando sea necesario.
- Permite a los usuarios acceder, exportar y eliminar sus datos. Necesitas endpoints de API para esto.
- Mantén los datos seguros. Cifrado, controles de acceso, registros de auditoría.
- Reporta brechas rápido. Tienes 72 horas para notificar a las autoridades después de descubrir una brecha.
- Documenta todo. Tus actividades de procesamiento, tus medidas de seguridad, tus flujos de datos.
Ese es el resumen práctico. El resto de esta guía te muestra cómo implementar cada requisito.
Los 7 Requisitos Técnicos Clave
1. Gestión del Consentimiento
El consentimiento debe ser libre, específico, informado e inequívoco. Las casillas premarcadas no cuentan. El consentimiento agrupado (“acepta todo”) no cuenta. La retirada debe ser tan fácil como dar el consentimiento.
Qué Construir
Un sistema de consentimiento necesita tres componentes:
- Un almacén de registros de consentimiento. Para cada usuario, registra a qué consintió, cuándo y cómo.
- Un mecanismo de verificación de consentimiento. Antes de procesar datos para un propósito específico, verifica que el usuario tiene consentimiento activo.
- Un mecanismo de retirada. Permite a los usuarios revocar el consentimiento a través de tu interfaz, y detén el procesamiento inmediatamente.
Esquema de Base de Datos
CREATE TABLE user_consents (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id),
consent_type VARCHAR(100) NOT NULL,
granted BOOLEAN NOT NULL,
granted_at TIMESTAMPTZ,
revoked_at TIMESTAMPTZ,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_user_consents_lookup
ON user_consents (user_id, consent_type, granted);
Almacena el historial completo. Nunca elimines ni sobrescribas registros de consentimiento. Cuando un usuario revoca el consentimiento, inserta una nueva fila con granted = false y establece revoked_at. Esto te da un rastro de auditoría.
Middleware de Verificación de Consentimiento
Aquí hay un middleware de Express que verifica el consentimiento antes de procesar una solicitud:
import { Request, Response, NextFunction } from "express";
import { db } from "./database";
interface ConsentRequirement {
type: string;
required: boolean;
}
function requireConsent(consentType: string) {
return async (req: Request, res: Response, next: NextFunction) => {
const userId = req.user?.id;
if (!userId) {
return res.status(401).json({ error: "Authentication required" });
}
const consent = await db.query(
`SELECT granted FROM user_consents
WHERE user_id = $1 AND consent_type = $2
ORDER BY created_at DESC
LIMIT 1`,
[userId, consentType]
);
if (!consent.rows[0]?.granted) {
return res.status(403).json({
error: "Consent required",
consentType,
message: `You must grant "${consentType}" consent to use this feature.`,
consentUrl: `/settings/privacy`,
});
}
next();
};
}
// Usage
app.post(
"/api/newsletter/subscribe",
requireConsent("marketing_emails"),
subscribeHandler
);
app.post(
"/api/analytics/track",
requireConsent("usage_analytics"),
trackHandler
);
2. Acceso y Exportación de Datos (Derecho de Acceso)
Los usuarios tienen derecho a solicitar una copia de todos los datos personales que almacenas sobre ellos. Debes proporcionarla en un formato de uso común y legible por máquina. JSON o CSV funcionan bien.
Qué Construir
Un endpoint que recopile todos los datos personales de un usuario en todas las tablas y servicios, y los empaquete en un archivo descargable.
interface DataExport {
exportedAt: string;
user: {
profile: Record<string, unknown>;
activity: Record<string, unknown>[];
consents: Record<string, unknown>[];
communications: Record<string, unknown>[];
};
}
app.get("/api/me/data-export", authenticate, async (req, res) => {
const userId = req.user.id;
const [profile, activity, consents, communications] = await Promise.all([
db.query("SELECT id, email, name, created_at FROM users WHERE id = $1", [
userId,
]),
db.query(
"SELECT action, metadata, created_at FROM user_activity WHERE user_id = $1 ORDER BY created_at DESC",
[userId]
),
db.query(
"SELECT consent_type, granted, granted_at, revoked_at FROM user_consents WHERE user_id = $1 ORDER BY created_at DESC",
[userId]
),
db.query(
"SELECT type, sent_at, subject FROM communications WHERE user_id = $1 ORDER BY sent_at DESC",
[userId]
),
]);
const exportData: DataExport = {
exportedAt: new Date().toISOString(),
user: {
profile: profile.rows[0],
activity: activity.rows,
consents: consents.rows,
communications: communications.rows,
},
};
res.setHeader("Content-Type", "application/json");
res.setHeader(
"Content-Disposition",
`attachment; filename="data-export-${userId}.json"`
);
res.json(exportData);
});
Este endpoint debe cubrir cada tabla que contenga datos del usuario. Audita tu esquema a fondo. Una tabla faltante significa una exportación incompleta, lo cual es un fallo de cumplimiento.
3. Derecho de Supresión (Derecho al Olvido)
Los usuarios pueden solicitar que elimines todos sus datos personales. Debes cumplir a menos que tengas una obligación legal de retenerlos (como registros fiscales o prevención de fraude).
Qué Construir
Un endpoint de eliminación que elimine o anonimice datos del usuario en todas las tablas. Esto es más difícil de lo que parece debido a las restricciones de clave foránea y datos de los que dependen otros sistemas.
app.delete("/api/me/account", authenticate, async (req, res) => {
const userId = req.user.id;
const client = await db.getClient();
try {
await client.query("BEGIN");
// Anonymize data that must be retained for business records
await client.query(
`UPDATE orders
SET customer_name = 'deleted', customer_email = 'deleted'
WHERE user_id = $1`,
[userId]
);
// Delete data that can be fully removed
await client.query("DELETE FROM user_activity WHERE user_id = $1", [
userId,
]);
await client.query("DELETE FROM user_consents WHERE user_id = $1", [
userId,
]);
await client.query("DELETE FROM communications WHERE user_id = $1", [
userId,
]);
await client.query("DELETE FROM sessions WHERE user_id = $1", [userId]);
// Anonymize the user record instead of deleting
// This preserves referential integrity
await client.query(
`UPDATE users SET
email = 'deleted-' || id || '@removed.invalid',
name = 'Deleted User',
phone = NULL,
address = NULL,
deleted_at = NOW()
WHERE id = $1`,
[userId]
);
await client.query("COMMIT");
// Trigger deletion in external systems
await Promise.allSettled([
emailService.deleteSubscriber(userId),
analyticsService.deleteUser(userId),
searchIndex.removeUser(userId),
]);
res.json({ message: "Account and personal data deleted" });
} catch (error) {
await client.query("ROLLBACK");
throw error;
} finally {
client.release();
}
});
Decisiones clave:
- Eliminar vs. anonimizar. Los registros necesarios para contabilidad (pedidos, facturas) deben anonimizarse. Elimina todo lo demás.
- Sistemas externos. Los datos enviados a servicios de terceros deben eliminarse allí también.
- Plazo. El GDPR dice “sin dilación indebida.” Completa la eliminación en 30 días. Para la mayoría de sistemas, hazlo inmediato.
4. Minimización de Datos
Solo recoge y almacena los datos que realmente necesitas para un propósito declarado. Si pides un número de teléfono pero nunca llamas a los usuarios, no deberías estar recogiéndolo.
Reglas Prácticas
- Audita cada campo de formulario. Para cada campo, pregunta: “¿Qué funcionalidad específica se rompe si eliminamos esto?” Si la respuesta es nada, elimínalo.
- Establece períodos de retención. No guardes datos para siempre. Define cuánto tiempo se necesita cada tipo de dato, luego elimínalos automáticamente.
- Minimiza el logging. Elimina datos personales de las entradas de log. Registra IDs de usuario, no nombres o emails.
-- Automatic data retention with PostgreSQL
-- Run this as a scheduled job (e.g., pg_cron)
DELETE FROM user_activity
WHERE created_at < NOW() - INTERVAL '2 years';
DELETE FROM session_logs
WHERE created_at < NOW() - INTERVAL '90 days';
DELETE FROM password_reset_tokens
WHERE created_at < NOW() - INTERVAL '24 hours';
5. Cifrado
El GDPR requiere “medidas técnicas apropiadas” para proteger los datos personales. El cifrado es la más importante.
En Reposo
- Cifra el disco de tu base de datos. Todos los proveedores de cloud principales lo soportan. Actívalo y verifica.
- Para campos altamente sensibles (números de seguridad social, datos de salud), añade cifrado a nivel de aplicación por encima.
- Cifra los backups. Un backup sin cifrar es una brecha esperando ocurrir.
En Tránsito
- TLS en todas partes. Cada conexión entre servicios, bases de datos y usuarios. Sin excepciones.
- Fuerza HTTPS. Redirige HTTP. Establece headers HSTS.
- Usa TLS para conexiones a base de datos. PostgreSQL lo soporta nativamente.
// PostgreSQL connection with TLS
import { Pool } from "pg";
const pool = new Pool({
host: process.env.DB_HOST,
port: 5432,
database: process.env.DB_NAME,
user: process.env.DB_USER,
password: process.env.DB_PASSWORD,
ssl: {
rejectUnauthorized: true,
ca: fs.readFileSync("/path/to/server-ca.pem").toString(),
},
});
6. Notificación de Brechas
Si los datos personales se ven comprometidos, debes notificar a la Autoridad de Protección de Datos pertinente en 72 horas. Si la brecha presenta un alto riesgo para los individuos, también debes notificar a los usuarios afectados.
Qué Construir
- Registro de auditoría. Registra cada acceso a datos personales. Quién accedió, cuándo y desde dónde.
- Detección de anomalías. Alerta sobre patrones de acceso inusuales (exportaciones masivas de datos, acceso desde nuevas IPs, acceso fuera de horario laboral).
- Un plan de respuesta a incidentes. Documenta quién hace qué cuando se detecta una brecha. Esto no es código. Es una lista de verificación que tu equipo practica.
CREATE TABLE data_access_log (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL,
accessed_by UUID NOT NULL,
access_type VARCHAR(50) NOT NULL,
resource_type VARCHAR(100) NOT NULL,
resource_id UUID,
ip_address INET,
user_agent TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_data_access_log_user
ON data_access_log (user_id, created_at);
CREATE INDEX idx_data_access_log_accessor
ON data_access_log (accessed_by, created_at);
7. Privacidad por Diseño
El GDPR dice que la privacidad debe estar integrada en los sistemas desde el principio, no añadida después. En la práctica, esto significa hacer de la privacidad el comportamiento predeterminado.
- Predeterminado a privado. Las nuevas funcionalidades deben recoger datos mínimos y requerir opt-in para cualquier cosa más allá de la función principal.
- Los ajustes predeterminan la opción más privada. Los usuarios que nunca tocan sus ajustes deben tener la mayor protección de privacidad.
- Separa las preocupaciones. No mezcles datos de analítica con datos funcionales. No reutilices tokens de autenticación para tracking.
Anonimización vs. Pseudonimización
No son lo mismo, y la distinción importa.
- Pseudonimización reemplaza la información identificativa con un token reversible. Ejemplo: hashear direcciones de email. Si tienes la función hash y el email original, puedes re-identificar a la persona. El GDPR sigue aplicándose porque la re-identificación es posible.
- Anonimización elimina la información identificativa permanentemente. Ejemplo: analítica agregada (“1.247 usuarios visitaron la página de precios”) sin forma de identificar qué usuarios. El GDPR no se aplica a datos verdaderamente anonimizados.
La verdadera anonimización es difícil. Si tu conjunto de datos “anónimo” incluye una marca temporal, una ciudad y un tipo de dispositivo, esa combinación podría identificar de forma única a alguien. Sé conservador.
Consentimiento de Cookies
Si tu sitio web usa cookies más allá de lo estrictamente necesario, necesitas consentimiento antes de establecerlas.
Requiere consentimiento: cookies de analítica, píxeles de publicidad, widgets de redes sociales, cualquier script de tracking de terceros.
No requiere consentimiento: cookies de sesión, cookies de carrito de compra, tokens CSRF, la propia cookie de preferencia de consentimiento.
Tu banner de consentimiento debe bloquear las cookies no esenciales hasta que se dé el consentimiento, ofrecer opciones granulares y hacer “rechazar todo” tan fácil como “aceptar todo.” No construyas esto desde cero. Herramientas como Cookiebot manejan la complejidad. La regla clave: ningún script de tracking se ejecuta antes de obtener el consentimiento.
Procesadores de Datos de Terceros
Cada servicio de terceros que maneja los datos de tus usuarios es un “procesador de datos” bajo el GDPR. Tú eres responsable de su cumplimiento.
Qué Verificar
Antes de integrar cualquier servicio de terceros que toque datos personales:
- ¿Tienen un DPA? Un Acuerdo de Procesamiento de Datos es obligatorio. La mayoría de proveedores SaaS publican el suyo públicamente.
- ¿Dónde almacenan los datos? Si es fuera de la UE, verifica la base legal para la transferencia.
- ¿A qué datos acceden? Minimiza lo que envías. Si el servicio solo necesita un email, no envíes el perfil completo.
- ¿Puedes eliminar datos de sus sistemas? Las solicitudes de eliminación de usuarios deben propagarse a todas partes.
- ¿Cómo manejan las brechas? Su DPA debe especificar plazos de notificación.
Procesadores de Terceros Comunes a Revisar
- Servicios de email (Resend, SendGrid, Mailchimp)
- Analítica (Google Analytics, Mixpanel, Amplitude)
- Seguimiento de errores (Sentry, Bugsnag)
- Procesamiento de pagos (Stripe, Adyen)
- Hosting en la nube (AWS, Google Cloud, Vercel)
- Herramientas de atención al cliente (Intercom, Zendesk)
- APIs de IA (OpenAI, Anthropic, Google AI)
Mantén una lista de todos los procesadores. Revísala trimestralmente.
Políticas de Retención de Datos
No guardes datos personales más tiempo del necesario. Define períodos de retención para cada tipo de dato.
| Tipo de Dato | Retención Sugerida | Razón |
|---|---|---|
| Datos de cuenta de usuario | Hasta que se solicite la eliminación | Necesarios para el servicio |
| Registros de sesión | 90 días | Seguridad y depuración |
| Registros de actividad del usuario | 1-2 años | Analítica de producto |
| Tickets de soporte | 3 años | Calidad del servicio |
| Registros financieros | 7 años | Obligaciones fiscales/legales |
| Tokens de restablecimiento de contraseña | 24 horas | Seguridad |
| Intentos fallidos de inicio de sesión | 90 días | Monitorización de seguridad |
Implementa trabajos de limpieza automatizados. No confíes en que alguien recuerde ejecutar un script.
Lista de Verificación GDPR para Desarrolladores
Usa esto como punto de partida al construir o auditar un sistema.
Recopilación de Datos
- Cada campo de formulario tiene un propósito declarado
- No se recopilan datos innecesarios
- La política de privacidad está enlazada desde cada punto de recopilación de datos
- El consentimiento se recoge antes del procesamiento (cuando es necesario)
- Los registros de consentimiento se almacenan con marcas temporales
Almacenamiento de Datos
- El cifrado de base de datos en reposo está activado
- TLS está forzado para todas las conexiones
- Los campos sensibles tienen cifrado a nivel de aplicación
- Los backups están cifrados
- El acceso a datos de producción está restringido y registrado
Derechos del Usuario
- Existe un endpoint de exportación de datos que cubre todas las tablas
- Existe un endpoint de eliminación de cuenta que maneja todos los datos
- Los usuarios pueden ver y retirar consentimiento en sus ajustes
- La eliminación se propaga a servicios de terceros
- Todas las solicitudes de derechos de usuario se responden en 30 días
Cookies y Tracking
- El banner de consentimiento de cookies está implementado
- Las cookies no esenciales están bloqueadas antes del consentimiento
- Las opciones de consentimiento son granulares (no todo o nada)
- “Rechazar todo” es tan prominente como “Aceptar todo”
Terceros
- Todos los procesadores de datos están documentados
- Los DPAs están firmados con cada procesador
- Los datos enviados a terceros están minimizados
- La eliminación de datos de terceros es posible
Seguridad
- Los registros de auditoría rastrean el acceso a datos personales
- Las alertas de anomalías están configuradas
- El plan de respuesta a incidentes está documentado
- El proceso de notificación de brechas está definido (plazo de 72 horas)
Retención
- Los períodos de retención están definidos para todos los tipos de datos
- Los trabajos de limpieza automatizados están programados
- Los datos expirados realmente se están eliminando (verifica esto)
Reflexiones Finales
El cumplimiento del GDPR no es un proyecto puntual. Es un conjunto de prácticas integradas en cómo construyes software. El trabajo técnico es directo: almacenamiento de consentimiento, exportación de datos, endpoints de eliminación, cifrado, registro de auditoría. Ingeniería estándar.
La parte difícil es ser exhaustivo. Es fácil olvidarse de ese archivo de log, ese evento de analítica o esa integración de terceros que almacena emails de usuarios. Audita regularmente. Prueba tu endpoint de eliminación. Verifica que tus exportaciones están completas. Integra la privacidad en tu proceso desde el principio.
¿Necesitas ayuda para construir software conforme con el GDPR o auditar tus sistemas existentes? Contáctanos. Construimos aplicaciones con privacidad como prioridad para empresas europeas y compañías que sirven a usuarios de la UE.