app/services/.
Data governance API
All governance endpoints require thegovernance:write or governance:read scope. Only users with the admin role have these scopes by default.
Base path: /v1/governance/
Retention policies
Retention is configured per-workspace inworkspace_settings. Each class of data has its own retention window:
How retention enforcement works
app/services/retention.py provides purge_expired(database_url), which:
- Fetches all workspace IDs
- For each workspace, reads the retention windows from
workspace_settings - Sets
app.current_workspaceGUC (so RLS applies) - Deletes rows older than the configured window from each table
The
purge_expired() function is implemented but not yet scheduled. It must be called by an external cron job or scheduled worker. A periodic task that calls purge_expired(DATABASE_URL) on a daily schedule is the recommended integration. Automated scheduling is on the SOC 2 roadmap — see SOC 2 readiness.audit_log_retention_days is set below this, the purge skips audit log rows to prevent premature deletion of evidence.
Right-to-be-forgotten (RTBF — GDPR Article 17)
Causeloop implements a multi-step RTBF workflow with state tracking and an erasure certificate.RTBF states
Submitting a request
subject_ref. The plaintext email is only used to identify the subject during processing and is not retained beyond the request record.
Duplicate guard: if an active RTBF request already exists for the same subject in the same workspace, the API returns 409 Conflict.
SLA: the due_at field is set to 30 days from received_at, corresponding to GDPR’s response deadline.
Approving and executing erasure
erase_workspace() from app/services/rtbf.py, which:
- Resolves the workspace’s organization slug
- Executes hard deletes of the subject’s data across tenant tables
- Records a persistent erasure record
erase_workspace() requires DATABASE_URL to be available at runtime. When the application is running against the in-memory store (no DATABASE_URL), the approve endpoint records the approval transition but cannot execute the physical deletion. In production with Postgres, the deletion executes synchronously on approval.Erasure certificate
Once a request reaches thecompleted state, the erasure certificate is available:
Tenant data export
The export service (app/services/tenant_export.py) assembles a complete snapshot of a workspace’s business data. It runs RLS-scoped so it can only access the requesting workspace’s rows.
What is exported
Intentionally excluded:
config_encrypted (connector credentials), secret_encrypted (webhook secrets), and all other secret columns. These are never included in exports.
Requesting an export
The current export implementation returns data inline in the response body. Export delivery to object storage (S3/GCS presigned URLs) with checksums is planned. See SOC 2 readiness for the current status.
Data residency
Causeloop does not enforce data residency at the application layer — residency is determined by where you run the database. For EU data residency:- Use Neon’s EU region (Frankfurt) when creating your Neon project
- Deploy the API to an EU region (Hetzner Falkenstein/Helsinki, Railway EU, Render Frankfurt)
- Configure your LLM provider’s EU endpoint if available, or use the mock provider
Offboarding and full tenant deletion
To permanently delete all data for a tenant (not just an individual), useoffboard_client():