Skip to content

Overview

Privacy Center helps you manage privacy requests, consent records, policy evidence, and retention rules. Verified delete requests can run registered anonymisation and erasure work when they are marked fulfilled; access and export delivery still follows your approved operational process.

  • Privacy requests: submitted, processing, fulfilled, rejected, and overdue data requests.
  • Consent records: who consented to what, and when.
  • Policy acceptances: read-only records of a subject accepting a policy version.
  • Consent policies: versioned policy-evidence records, including cookie-policy records.
  • Retention rules: active data-minimisation rules with dry-run and run-now actions.
  • Verify, fulfill, or reject a data request.
  • Keep and review consent records.
  • Manage consent-policy records and review the public preference-centre evidence.
  • Track a request from received to fulfilled.
  • Dry-run a retention rule before applying it.

Go to Privacy center in the admin to handle requests, review consent, and manage policies and retention rules.

Set a stable CAPELL_PRIVACY_CENTER_HASH_SECRET before collecting evidence. The application key is the fallback, but if neither value exists, consent, policy-acceptance, and request actions that need an identity hash fail instead of using a guessable salt. Changing the secret changes every future hash, so existing email, IP, and user-agent hashes will no longer compare with newly supplied identifiers.

Permissions are separate by resource. Consent records and policy acceptances are read-only and require their ViewAny or View permissions. Privacy requests additionally require Update:PrivacyRequest for the edit workflow. Consent policies and retention rules use their matching Create, Update, and Delete permissions. Global actors bypass these permission checks.

The current resource queries are portfolio-wide rather than filtered to an operator’s assigned sites. A user with a ViewAny permission can see list rows from other sites and records whose site is blank; the policy checks assigned sites only when a particular record is opened or changed. The create forms also accept a numeric site ID directly. Give all Privacy Center list and create permissions only to portfolio-trusted operators.

The overview widget is controlled by its admin/super-admin role setting rather than these resource permissions. Its counts cover every site and are cached for up to five minutes.

The cache-safe public preference center is available at /privacy/consent. A save is CSRF-protected and rate-limited to 30 requests per minute per IP. It writes one new consent row for every category: Essential is always granted, selected optional categories are granted, and every unselected category is denied.

This is an append-only evidence flow. Repeated saves create another full set of rows rather than updating or revoking the earlier set. Public submissions are not linked to a site, subject, or policy version; they store salted IP and user-agent hashes plus public_preferences evidence. They are therefore shared records in the admin access model.

The response sets a capell_privacy_consent_saved marker cookie for 180 days, but it does not store the selected categories in that cookie. The preferences page does not load earlier choices and will show optional categories unchecked on the next visit.

Privacy Center does not automatically inject its banner partial, block scripts, or switch analytics and marketing services from the saved choices. Render a link or banner in the theme and make each consuming integration enforce the applicable category. A consent-policy record stores identity, version, dates, and an optional content hash, not the policy document itself; the public preference submission does not automatically attach one.

There is no create screen or public DSAR form. An integration must call OpenPrivacyRequestAction, normally with the resolved subject model as well as the request details. New requests receive a unique reference and a due date 30 days after submission by default.

In the admin, Mark verified moves Submitted or Verifying to Processing. Mark fulfilled is shown only for Processing, while Reject is available until a request is fulfilled, rejected, or cancelled. The underlying Actions do not themselves enforce every UI transition, so integrations must apply the same verification gate.

For access, export, rectification, restriction, and objection requests, fulfilment records the status, time, and workflow payload only. BuildPrivacyExportAction can assemble Privacy Center rows and registered package exports into an in-memory data object, but the resource has no build, download, email, or secure-delivery action.

A Delete request cannot be fulfilled unless its linked subject still resolves. Fulfilment clears that subject’s links, hashes, evidence, and metadata in Privacy Center, then runs every contributor in the cross-package subject-data export/erasure registry. It does not inherently delete the subject model itself; only registered package erasers handle their own records. If a contributor throws, fulfilment stops and the request is not marked fulfilled; resolve the failure before retrying.

Workflow payloads, request metadata, rejection reasons, consent evidence, and policy metadata are ordinary plaintext database values. Email, IP, and user-agent evidence is hashed rather than encrypted; subject model types and IDs remain ordinary relational values until anonymisation. Restrict database and backup access accordingly.

Treat Retention rules as destructive administrator tooling:

  • Record type must be a fully qualified Eloquent model class even though the form allows it to be blank. An active blank or invalid class fails the retention run.
  • A rule with a site ID adds a site_id filter; a blank site applies across all sites. Data domain, Legal basis, and Metadata are descriptive and do not narrow the query.
  • A retention period of zero is accepted and matches records dated up to the time of the run. Use an intentional positive period unless immediate whole-scope processing is genuinely required.
  • The cutoff uses decided_at for consent records, accepted_at for policy acceptances, submitted_at for privacy requests, and created_at for every other model.
  • Delete issues a bulk model-query delete. The package-owned privacy models are not soft-deletable, so this is irreversible for them. Anonymize clears the defined identity/evidence fields only for Consent Record, Policy Acceptance, and Privacy Request; for any other model it merely updates updated_at and does not anonymise its data. Review writes a retention_review entry into the record’s metadata and fails when the target does not support that field.
  • Dry run counts matching rows without changing them. Run now applies the selected rule even when it is inactive. Always dry-run against a current backup before enabling or running Delete.

The custom Dry run and Run now table actions do not add separate update authorisation. A user who can list retention rules can trigger either action for any visible rule, including another site’s rule, so ViewAny:RetentionRule is itself operationally sensitive.

The package schedules privacy:apply-retention daily with overlap prevention and single-server locking. Only active rules are included in that scheduled command. Keep Laravel’s scheduler running; one invalid rule or execution exception stops the command before later rules run. There is no immediate per-rule retry, so the next daily run is the next automatic attempt.

  • Marking a verified Delete request fulfilled runs configured erasure contributors; access and export delivery are handled through your approved process.
  • Consent records and policy acceptances are evidence ledgers, not editable preference profiles.
  • Site deletion cascades its site-linked privacy records. Shared records with no site remain.

Privacy Center ships a public cookie consent preference center. The cache-safe public preference center is backed by RecordConsentAction. RecordConsentAction can infer a subject from a source model when another package mirrors consent, but only when that package has already loaded a subject or visit relation.

Subject-data handling uses the cross-package subject-data export/erasure registry. Public DSAR intake is not shipped yet, so requests must be opened through OpenPrivacyRequestAction directly or through another package’s controlled admin workflow.


For how to use Privacy Center, see the admin guide. For developers: see the README.