Compliance Scaffold — UK / EU / US
This template ships a compliance scaffold — the wiring buyers need to operate under UK GDPR, EU GDPR, US state privacy laws, and adjacent regulations. The scaffold is not legal advice, and shipping the scaffold does not make a buyer compliant on its own. The buyer is the compliant party.
This document is the contract: what the kit does for the buyer, and what the buyer must still do for themselves.
Template Empire validates this scaffold against its internal compliance standard and Gate 17 release checklist before packaging.
What ships in the scaffold
| Area | Where it lives | What you get |
|---|---|---|
| Legal pages | /privacy, /terms, /cookie-policy, /accessibility, /dmca, /do-not-sell | Skeleton copy with structurally-correct headings, region-conditional rendering for US-only pages, GDPR-rights enumeration on the privacy page. |
| Footer | src/components/landing/footer.tsx | Renders registered legal entity (company number, registered office, jurisdiction) and region-conditional legal links. Reads everything from SITE_CONFIG.legalEntity. |
| Cookie banner | src/components/ui/cookie-consent.tsx | Accept all and Reject all at visual parity (Gate 17 #8 P0). Honours navigator.globalPrivacyControl. Mirrors choice to a httpOnly server cookie. |
| GPC server | src/proxy.ts + src/lib/compliance/consent.ts | Middleware honours Sec-GPC: 1 even on the very first request (auto-records deny). getConsent(request) and getAnalytics(request) helpers for route handlers. |
| DSAR endpoint | POST /api/account/export | Authenticated user gets a JSON download of every row holding their personal data. Audit-logged. Rate-limited 5/hr. |
| Erasure endpoint | POST /api/account/delete | Soft-delete + 30-day grace window + scheduled hard-delete via pnpm db:cleanup. Anonymises PII columns immediately, revokes all sessions, fires optional outbound webhook for third-party tools. |
| Audit log | audit_log table in initial migration | Auto-written for login, logout, signup, password_reset, email_change, consent.updated, account.deletion_requested, data_export.requested, etc. Pruned after auditLogRetentionDays. |
| PCI DSS posture | src/services/billing.service.ts (when present) | Stripe Checkout / Elements only — no raw card data ever touches this database. Buyer stays in PCI DSS SAQ-A. |
What stays with you (the buyer)
- Real privacy policy wording for your specific data flows, sub-processors, and retention windows.
- DPA signing with each sub-processor (Supabase, Stripe, Vercel, Resend, etc.).
- DPIA (Data Protection Impact Assessment) for any high-risk processing.
- DPO appointment if you're an EU public body or large-scale special-category processor.
- ICO registration if you're in the UK and process personal data (£52/year for most controllers).
- Sales tax / nexus calculation — Stripe Tax is the easiest route; the kit links it but doesn't configure it.
- UGC content moderation — the UK Online Safety Act 2023 + DMCA require active moderation tooling if you allow user-generated content.
- COPPA registration if your service is directed at users under 13.
- Trust mark registration (ISO 27001, SOC 2) if you market enterprise — the kit makes this easier but doesn't grant it.
Pre-launch checklist
Before going live, complete every item below:
SITE_CONFIG.legalEntity— fill incompanyName,companyNumber,placeOfRegistration,registeredAddress,jurisdiction, andvatNumber(if applicable).SITE_CONFIG.regions— set every region you actually sell to (NOT just where you're registered).SITE_CONFIG.compliance.dmca.*— fill in your DMCA agent details ifregions.usis true.SITE_CONFIG.compliance.modernSlaveryStatementUrl— set if your turnover is ≥ £36m.SITE_CONFIG.contact.privacy— replace the placeholder with a monitored mailbox.SITE_CONFIG.legalEffectiveDate— bump to your launch date.- Privacy / Terms / Cookie / Accessibility / DMCA / Do-Not-Sell pages — review the scaffold copy, replace placeholder paragraphs, run past your lawyer.
- Sign DPAs with every sub-processor.
- Set up the daily cron for
pnpm db:cleanupso the hard-delete sweep, audit-log pruning, and token cleanup all run. The script writes anaccount.deletion_completedaudit-log row for every user it hard-deletes so the chain of custody is provable. DELETION_WEBHOOK_URLin.env— set if you use third-party tools (Mailchimp, Intercom, Mixpanel, etc.) that hold their own copy of user data; the deletion route POSTs{ userId, deletedAt }so they can purge their copy.- Audit-log retention and deletion-grace windows are configured in
SITE_CONFIG.compliance.{auditLogRetentionDays, deletionGraceDays}(NOT env vars). Defaults: 365-day retention, 30-day grace. SetauditLogRetentionDays: 0to disable retention pruning entirely.
Subject-rights request runbook
When a user (or a regulator) sends a DSAR or erasure request to your privacy mailbox:
- DSAR / right of access: point them at
Settings → Privacy → Download my data(calls/api/account/export). If they need a manual export, runpnpm dsar <userId>or run the route via curl with the user's session token. You have 30 days under UK/EU GDPR (extendable to 90 for complex requests, with notice). - Right to erasure: point them at
Settings → Delete account(calls/api/account/delete). The hard-delete completes 30 days later via the cleanup cron. You have 30 days under UK/EU GDPR. - Right to rectification: most fields are user-editable in the profile UI. For fields that aren't, fix in DB and write an
audit_logentry. - Right to portability: the DSAR JSON export IS the portable format. No additional work.
- Right to object / restrict: flip the relevant
notification_preferencesrow, or set the user's account topausedif you implement that.
Auditor-friendly queries
-- Outstanding deletion requests (still in grace window)
SELECT id, deleted_at, deleted_at + INTERVAL '30 days' AS hard_delete_at
FROM users WHERE deleted_at IS NOT NULL ORDER BY deleted_at;
-- Recent consent changes
SELECT user_id, action, details, created_at
FROM audit_log WHERE action = 'consent.updated' ORDER BY created_at DESC LIMIT 50;
-- DSAR requests in the last 90 days
SELECT user_id, created_at
FROM audit_log WHERE action = 'data_export.requested'
AND created_at > NOW() - INTERVAL '90 days' ORDER BY created_at DESC;
Last reviewed against: UK GDPR; UK Data (Use and Access) Act 2025; UK Companies Act 2006 §82; UK ePrivacy Regulations (PECR); UK DMCC 2025 §29; UK Modern Slavery Act 2015 §54; EU GDPR; EU AI Act 2024/1689; EU Accessibility Act 2025; CCPA/CPRA + 19 US state privacy laws; ADA Title III + DOJ April 2026 rule; DMCA §512; CalOPPA.
See Template Empire's compliance standards for how every kit is held to — and audited against — these requirements.