mcpField
D
data-retention-policies

data-retention-policies

github.com/finsilabs数据与数据库6084 次安装5 天前更新
代码仓库

关于 data-retention-policies

面向电商团队的数据保留政策技能,帮助制定保留期限、归档与清除规则,并按平台规划实施。重点涵盖 GDPR 请求、订单个人信息匿名化及跨系统删除审计。

主要功能

  1. 01制定数据保留计划
  2. 02Shopify、WooCommerce 与 BigCommerce 配置建议
  3. 03订单个人信息匿名化
  4. 04跨服务删除与审计日志
  5. 05分批安排定期清理

适用场景

  1. 01准备数据保护审计或 SOC 2 评估
  2. 02处理 GDPR 数据访问或删除请求
  3. 03降低无管控数据积累带来的存储成本

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill data-retention-policies

安装后在 Claude Code 中输入/data-retention-policies确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

tile.json
evals/gdpr-customer-purge-with-legal-hold-and-/
criteria.json
task.md
evals/order-pii-anonymization-preserving-finan/
criteria.json
task.md
evals/retention-schedule-and-automated-purge-j/
criteria.json
task.md

详细介绍

数据保留政策

概述

数据保留政策规定每类数据的保存时长、归档时间和清除时间。电商商店必须在法律义务(税务记录通常必须保存 5–7 年)与隐私法规(GDPR 的数据最小化原则要求删除不再需要的数据)之间取得平衡。合适的做法取决于你的平台:Shopify 会自动处理部分数据保留,而 WooCommerce/自定义商店则需要明确实施相关措施。

何时使用此技能

  • 为新的或现有的电商平台实施 GDPR 数据最小化要求时
  • 法务或合规团队要求制定书面数据保留政策时
  • 准备数据保护审计或 SOC 2 Type II 评估时
  • 数据无序累积导致存储成本不断增长时
  • 客户提交数据主体访问请求,而你需要确切了解其数据存储位置时

核心说明

步骤 1:先记录保留期限

在配置任何工具之前,先记录数据保留期限。法务、合规和工程团队必须在实施前达成一致。根据 GDPR 第 30 条,大型数据处理方必须制定此类处理活动记录(RoPA),建议所有组织都制定:

数据类别保留期限期限届满后的操作法律依据
订单(财务记录)7 年匿名化 PII;保留财务数据税法(美国 IRS、欧盟 VAT)
发票7 年归档至冷存储税务合规
客户账户最后活动后 3 年删除合法利益
会话/登录日志90 天删除合法利益
营销邮件同意记录直到取消订阅取消订阅时删除GDPR 同意
弃置购物车数据30 天删除合法利益
欺诈/安全日志90 天匿名化合法利益
分析事件13 个月汇总后删除合法利益

核心原则:法律要求保留的数据绝不可删除。对于订单,应将客户的 PII(姓名、电子邮件、地址)匿名化,同时保留财务记录(金额、税款、支付方式品牌/末 4 位)。

步骤 2:针对平台配置数据保留

Shopify

Shopify 默认会无限期保存订单数据,并负责处理基础设施组件层面的平台数据保留。

导出和删除客户数据(符合 GDPR): Shopify 提供内置的 GDPR Webhook:

  1. 前往 Settings → Customers → Customer privacy
  2. 当客户请求获取或删除其数据时,Shopify 会自动向所有已安装的应用发送 customers/data_request 和 customers/redact Webhook
  3. 对于你自己的应用或自定义代码,请为这些事件注册 Webhook 处理程序

手动匿名化客户信息:

  1. 打开客户记录 → More actions → Anonymize this customer
  2. Shopify 会用匿名占位信息替换 PII,同时保留订单记录
  3. 此操作不可逆,继续前请确认

自动清理邮件列表: 使用 Klaviyo(或你的邮件服务提供商)自动屏蔽或删除连续 12 个月以上未打开邮件的联系人。大多数邮件服务提供商都内置了“sunset”自动化功能。

导出数据以供归档:

  1. 前往 Customers → Export,将客户数据下载为 CSV 以供归档
  2. 对于订单:前往 Orders → Export
  3. 将导出文件存储在加密的冷存储中(例如,采用 Glacier 生命周期策略的 AWS S3)

WooCommerce

WooCommerce 不会自动执行数据保留。你需要通过插件和计划任务进行配置。

WooCommerce 内置清理功能:

  1. 前往 WooCommerce → 状态 → 工具
  2. 使用 清理 WooCommerce 会话 删除过期的会话数据
  3. 使用 WooCommerce 跟踪器清理 清除跟踪数据

GDPR / 数据保留插件: 安装 WP GDPR Compliance 或 GDPR Cookie Consent(由 WebToffee 提供):

  1. 前往 WP GDPR Compliance → 设置 → 数据保留
  2. 按数据类型配置保留期限
  3. 插件会通过 WP-Cron 创建计划清理任务

手动计划清理(WP-Cron):

// Add to your theme's functions.php or a custom plugin
// Schedule a daily cleanup job
if (!wp_next_scheduled('wc_data_retention_cleanup')) {
    wp_schedule_event(time(), 'daily', 'wc_data_retention_cleanup');
}

add_action('wc_data_retention_cleanup', 'run_data_retention');

function run_data_retention() {
    // Delete WooCommerce sessions older than 90 days
    global $wpdb;
    $wpdb->query(
        $wpdb->prepare(
            "DELETE FROM {$wpdb->prefix}woocommerce_sessions WHERE session_expiry < %d",
            time() - (90 * DAY_IN_SECONDS)
        )
    );
    // Log the cleanup
    error_log('WC data retention: cleaned sessions older than 90 days');
}

符合税务要求的订单 PII 匿名化: 不要删除订单(税务记录要求保留订单)。应在保留财务数据的同时,将 PII 匿名化。安装 WooCommerce GDPR(WebToffee),该插件会为订单添加“匿名化”操作。


BigCommerce

BigCommerce 在管理面板中提供客户数据管理工具。

导出客户数据:

  1. 前往 客户 → 导出 → 所有客户(CSV)
  2. 删除客户账户前,用于存档

删除客户:

  1. 前往 客户 → 找到该客户 → 删除
  2. 删除客户账户后,BigCommerce 会保留关联的订单记录

自动保留: BigCommerce 没有内置的计划数据保留功能。使用 BigCommerce Customers API 和 Orders API 来:

  1. 查询超过 3 年未活跃的客户
  2. 存档其数据
  3. 删除或匿名化其账户

这需要自定义脚本或第三方集成(例如通过 Zapier 或自定义应用)。


自定义 / 无头架构

对于自定义店面,应实现按计划运行的自动清除和匿名化任务。

关键原则:分批少量处理、避开高峰期运行,并始终记录日志:

// Run nightly at 2 AM UTC
import { CronJob } from 'cron';

new CronJob('0 2 * * *', runRetentionJobs).start();

async function runRetentionJobs() {
  const jobs = [
    { name: 'purge_sessions', fn: purgeSessions },
    { name: 'purge_abandoned_carts', fn: purgeAbandonedCarts },
    { name: 'anonymize_old_orders', fn: anonymizeOldOrders },
    { name: 'purge_inactive_customers', fn: purgeInactiveCustomers },
  ];

  for (const job of jobs) {
    try {
      const result = await job.fn();
      await db.retentionAuditLog.insert({ job: job.name, ...result, runAt: new Date() });
    } catch (err) {
      await alertOps(`Retention job failed: ${job.name}`, err);
    }
  }
}

// Paginated delete — avoids table locks
async function purgeSessions(): Promise<{ deleted: number }> {
  const cutoff = new Date(Date.now() - 90 * 86400_000);
  let deleted = 0;
  while (true) {
    const batch = await db.sessions.findExpired(cutoff, { limit: 1000 });
    if (batch.length === 0) break;
    await db.sessions.deleteBatch(batch.map(s => s.id));
    deleted += batch.length;
    await new Promise(r => setTimeout(r, 100)); // yield between batches
  }
  return { deleted };
}

// Anonymize order PII but keep financial data (7-year tax requirement)
async function anonymizeOldOrders(): Promise<{ anonymized: number }> {
  const cutoff = new Date(Date.now() - 7 * 365 * 86400_000);
  const orders = await db.orders.findWhere({ created_at: { lt: cutoff }, pii_anonymized_at: null }, { limit: 500 });
  for (const order of orders) {
    await db.orders.update(order.id, {
      customer_email:   `anon_${order.id}@deleted.invalid`,
      customer_name:    'Anonymous Customer',
      shipping_name:    'Anonymous',
      shipping_street:  null,
      shipping_city:    order.shipping_city,    // Keep for tax jurisdiction
      shipping_country: order.shipping_country,
      billing_name:     'Anonymous',
      billing_street:   null,
      // Financial data (total_amount, tax_amount, payment_method_last4): UNCHANGED
      pii_anonymized_at: new Date(),
    });
  }
  return { anonymized: orders.length };
}

跨服务删除客户数据: 删除客户时,应清除所有保存其数据的系统中的数据:

async function purgeCustomer(customerId: string, reason: 'gdpr_request' | 'inactivity') {
  // 1. Anonymize orders (keep for tax, remove PII)
  await anonymizeOrdersForCustomer(customerId);
  // 2. Delete from email platform (Klaviyo, Mailchimp)
  await emailPlatform.deleteContact(customerId);
  // 3. Delete from search index (Algolia, Elasticsearch)
  await searchIndex.deleteCustomer(customerId);
  // 4. Delete analytics identifier
  await analytics.deleteUser(customerId);
  // 5. Delete the customer profile
  await db.customers.anonymize(customerId);
  // 6. Log for compliance evidence
  await db.retentionAuditLog.insert({ action: 'customer_purged', customerId, reason, executedAt: new Date() });
}

最佳实践

  • 实施前先做好文档记录 — 法务、合规和工程团队必须就保留计划达成一致;工程团队单方面做出的决定会造成合规漏洞
  • 匿名化财务记录,绝不删除 — 订单必须保留至税务法定期限;将 PII 字段替换为匿名化占位符
  • 单独保留只追加的保留审计日志 — 这是向合规审计人员提供的证据;绝不要删除此日志中的内容
  • 在非高峰时段分批少量运行清除任务 — 使用 SELECT ... LIMIT n 分批处理,避免锁定表并影响实时流量
  • 将跨服务删除作为检查清单处理 — 涉及多个服务(数据库、电子邮件平台、分析系统)的清除操作必须可靠;分别记录每个系统的完成情况
  • 在 30 天内响应 GDPR 删除请求 — 构建带提醒和升级机制的自动化工作流;跟踪所有请求及其截止日期

常见问题

问题解决方案
保留任务锁定了生产表使用较小的批次(500–5000 行),为每条 DELETE/UPDATE 添加 LIMIT,并在流量较低时运行
清除了存在未解决争议或待处理订单的客户数据清除前检查是否存在待处理的拒付、未完成订单和有效订阅;实现法律保留机制
忘记搜索索引和分析数据仓库维护所有存储个人数据的系统清单;将每个系统纳入每个删除工作流
未在 30 天内完成 GDPR 删除请求构建带有 30 天截止日期跟踪器的自动化工作流;如果截止日期前 5 天仍未完成,则升级给人工处理
备份系统中保留了超出保留期限的数据标记已清除客户的 ID,以便在灾难恢复时还原备份后立即重新清除这些记录

相关技能

  • @gdpr-ecommerce
  • @account-security
  • @financial-audit-trail
  • @financial-compliance-sox

评论

支持 Markdown