GDPR & Compliance
The admin core provides all GDPR infrastructure out of the box. Child apps consume it via shared helper functions loaded through common.php — no configuration, no third-party services. All compliance data (consent records, login history, device sessions, export requests, deletion requests) stays in the admin main database.
What's Built In
Every compliance feature ships with the core and is available to all child apps automatically.
| Feature | Details |
|---|---|
| Consent versioning | Versioned legal documents with re-consent enforcement when terms change |
| Immutable consent audit trail | Append-only log of every consent grant and withdrawal — never updated or deleted |
| Data export (Article 20) | JSON or CSV export with automatic 7-day expiry |
| Account deletion (Article 17) | Right to erasure with 30-day cooling-off period |
| Login history tracking | Every login attempt recorded with IP, user agent, browser, method, and status |
| Device & session management | Per-device tracking with remote revocation (single device or all others) |
| Admin compliance dashboard | 5-tab user view: Profile, Consent, Login History, Sessions, Data & Deletion |
Consent Management
Consent is tracked through two tables in the admin main database:
consent_version
Stores versioned legal documents. Each document type can have multiple versions over time:
- Terms of Service (
tos) - Privacy Policy (
privacy_policy) - Marketing Email (
marketing_email) - Cookie Analytics (
cookie_analytics) - Cookie Marketing (
cookie_marketing)
When you publish a new version of any document, users who haven't accepted the latest version can be prompted to re-consent.
user_consent
An immutable audit log. Every consent action (grant or withdrawal) is appended as a new row — rows are never updated or deleted. This provides a complete, tamper-proof history of every user's consent decisions.
Helper Functions
// Record a consent action (grant or withdrawal)
record_consent($user_id, $consent_type, $action, $version_id);
// Get current consent status for a specific type
// Returns 'granted', 'withdrawn', or null (never consented)
get_consent_status($user_id, $consent_type);
// Get all consent statuses for a user (keyed by consent type)
get_all_consent_statuses($user_id);
// Get full audit trail with version labels
get_consent_history($user_id);
// Get the latest published version of a consent type
get_latest_consent_version($consent_type);
Registration Integration
During registration, new users must accept both Terms of Service and Privacy Policy before their account is created. Consent records are written immediately upon registration.
Re-Consent Flow
When you publish a new version of Terms of Service or Privacy Policy, the system automatically detects users who haven't accepted the latest version and requires them to re-consent before continuing.
- Admin publishes a new version of ToS or Privacy Policy in the compliance dashboard
- On the user's next login,
check_reconsent_needed()detects they haven't accepted the latest version - User is redirected to
auth/consent.php - User must review and accept the updated terms before entering the app
- A new consent record is appended to the audit trail
- User proceeds to the app as normal
Data Export (Article 20)
Users can request a portable copy of their personal data in JSON or CSV format, satisfying GDPR's right to data portability.
Helper Functions
// Request a data export (format: 'json' or 'csv')
request_data_export($user_id, $format);
// Collect export data from admin main DB + user's shard
build_export_data($user_id, $shard_id);
// Mark export as complete with file location and size
complete_data_export($export_id, $file_path, $file_size);
How It Works
build_export_data()collects data from both the admin main database and the user's shard database- Child apps extend the export by adding their own app-specific data on top of the base export
- Exports automatically expire after 7 days
build_export_data() first to get the base data, then append your app-specific data to the result before completing the export.
Account Deletion (Article 17)
Users can request permanent deletion of their account, satisfying GDPR's right to erasure. A 30-day cooling-off period allows users to change their mind.
Helper Functions
// Request account deletion (sets cancel_before date to 30 days from now)
request_account_deletion($user_id, $reason);
// Cancel a pending deletion during the cooling-off period
cancel_account_deletion($user_id);
// Check if a user has a pending deletion request
get_pending_deletion($user_id);
How It Works
- User requests deletion from their privacy page
- User must type DELETE to confirm the request
- A 30-day cooling-off period begins (the
cancel_beforedate is set) - During the cooling-off period, the user (or an admin) can cancel the request
- After 30 days, the account is permanently deleted
Login History
Every login attempt is recorded automatically — no setup required in child apps.
// Called automatically on every login attempt
record_login($user_id, $method, $status);
Methods
| Method | Description |
|---|---|
password | Standard email/password login |
oauth | OAuth 2.0 (Google, GitHub, Facebook) |
remember_me | Persistent cookie login |
saml | SAML 2.0 enterprise SSO |
2fa | Two-factor authentication verification |
Status
success— login succeededfailed— login failed (wrong password, expired token, etc.)
What's Captured
- IP address
- User agent string
- Parsed browser name
- Timestamp
Querying Login History
// Get paginated login history for a user
get_login_history($user_id, $limit, $offset);
// Get total count of login records
count_login_history($user_id);
Device & Session Management
Every login registers the device with browser, IP, and timestamp. Users can view and manage their active devices from their privacy page.
Helper Functions
// List all active devices for a user
get_user_devices($user_id);
// Revoke a single device (remote logout)
revoke_device($device_id, $user_id);
// Revoke all devices except the current one
revoke_all_other_devices($user_id, $current_cookie_id);
Where It's Managed
- Users — manage their own devices from the privacy page in any child app
- Admins — manage any user's devices from the compliance dashboard (Sessions tab)
Admin Compliance Dashboard
The admin panel includes a comprehensive compliance view for each user, organized into five tabs:
| Tab | Contents |
|---|---|
| Profile | User details, role, registration date, account status |
| Consent | Current consent statuses and full audit trail with version labels |
| Login History | Complete login log with method, status, IP, browser, timestamp |
| Sessions | Active devices with remote revocation controls |
| Data & Deletion | Export request history, pending deletion status, cancellation controls |
Admin Actions
From the compliance dashboard, admins can:
- Reset a user's password
- Revoke individual sessions or all sessions
- Cancel pending deletion requests
- View the full consent and login audit trails
All admin compliance actions are handled in userComplianceActions.php:
// Action handlers in userComplianceActions.php:
adminResetPassword // Force-reset a user's password
adminRevokeSession // Revoke a single device session
adminRevokeAllSessions // Revoke all sessions for a user
adminCancelDeletion // Cancel a pending account deletion
Child App Integration
All compliance functions are available the moment a child app includes common.php — zero configuration required.
What You Get for Free
- All consent, login history, device, export, and deletion functions
- A working privacy page (
views/privacy.php) in the child-app template with five sections: consent management, login history, active devices, data export, and account deletion - Re-consent enforcement across all apps
Extending Data Exports
Child apps can add their own app-specific data to the base export:
$base = build_export_data($user_id, $shard_id);
// Add child-app specific data
$base['items'] = get_user_items($user_id);
$base['preferences'] = get_user_prefs($user_id, $shard_id);
record_consent(), request_data_export(), request_account_deletion(), etc.) to interact with compliance data. Writing directly to the admin main database bypasses validation, audit logging, and version checks.