← Back to home · Privacy policy · ROPA · DPA
Data Retention Policy
Version 1.1 — 14 August 2026
This policy operationalises the GDPR storage limitation principle (Art. 5(1)(e)) for every category of personal data TravelCS processes — both as a controller (operator accounts, marketing leads, platform telemetry) and as a processor (operator-owned customer data). For each category we publish the retention period, the deletion trigger, the legal basis and the disposal method.
1. Scope
Applies to all personal data stored in TravelCS production systems, backups and sub-processor environments. Operator-specific overrides are permitted where the operator documents a different lawful retention period in their own privacy notice; the shorter period always wins.
2. Retention schedule
| Ref | Category | System / table | Retention period | Deletion trigger | Legal basis | Disposal |
|---|---|---|---|---|---|---|
| R1 | Operator admin & employee accounts | auth.users, operator_employees, operator_members | Active life of the account + 30 days | Account closure request OR 24 months of continuous inactivity. Operator-employee specific lifecycle triggers (stale invites, disabled seats, dormant active seats) are detailed in R1b. | Art. 6(1)(b) contract; Art. 5(1)(e) storage limitation | Hard delete from primary store; purge from daily backups within 30 days |
| R1b | Operator employee seats (churned / inactive) | public.operator_employees (status, last_active_at, updated_at) | Disabled seat: 30 days after status='disabled' (matches R1 backup tail). Stale invite: 90 days after status='invited' without acceptance. Dormant active seat: auto-disabled after 24 months without sign-in (then re-enters the 30-day Disabled clock). | status='disabled' for ≥30 days → hard delete. status='invited' for ≥90 days without conversion → hard delete. status='active' AND coalesce(last_active_at, updated_at) older than 24 months → auto-disable (does not delete immediately, preserves audit attribution). | Art. 5(1)(e) storage limitation; Art. 6(1)(b) contract (seat no longer needed for the operator's service); Art. 32(1)(b) integrity (revoke dormant credentials) | Hard delete of the operator_employees row; team_invites cascade-delete; team_audit_logs.employee_id is preserved with the foreign key set to NULL so the audit trail (Art. 5(2) accountability) survives the seat. Enforced daily by pg_cron job 'retention-purge-daily' via public.purge_inactive_operator_employees(); every run audited to public.retention_purge_log under rule_ref='R1b-disabled', 'R1b-stale-invite', 'R1b-auto-disabled' (migrations/061_operator_employees_lifecycle.sql). |
| R2 | Landing-page leads (marketing enquiries) | public.leads, public.landing_leads | 12 months from capture | 12-month rolling window OR earlier opt-out / erasure request | Art. 6(1)(f) legitimate interest (commercial follow-up); Art. 5(1)(e) | Monthly automated purge; converted leads migrate to R3 (operator-owned) |
| R3 | Booking leads & customer contact details | public.booking_leads | 24 months after last interaction (operator default; configurable per operator) | No inbound or outbound message for 24 months | Operator's Art. 6(1)(b) / (f) basis — TravelCS retains as processor on instructions | Soft-delete + 30-day grace, then hard delete; DSAR erasure honoured immediately |
| R4 | Channel message bodies (email incl. Gmail, WhatsApp, web chat) | public.messages (thread context: public.conversations) | Retained for the lifetime of the workspace. There is currently no automatic age-based purge. Users may request deletion of retained data through a verified data deletion request, which TravelCS processes within 30 days subject to applicable legal retention requirements. | Workspace/operator deletion, or a verified data deletion request. No scheduled age-based job deletes message bodies today. | Operator's Art. 6(1)(b) basis; Art. 5(1)(c) minimisation | Manual, verified erasure by an authorised administrator (hard delete of the row); operator deletion removes the rows and creates the R11 30-day recovery snapshot. |
| R4b | Message attachments (metadata + stored files) | public.message_attachments (rows) + Supabase Storage bucket 'message-attachments' (objects, path {operator_id}/{conversation_id}/{message_id}/{file}) | Retained for the lifetime of the workspace. No automatic age-based purge. Deletion available on verified request within 30 days. | Verified data deletion request, or manual administrator action. | Operator's Art. 6(1)(b) basis; Art. 5(1)(e) storage limitation | Database rows are removed with their parent message. Stored attachment files in the 'message-attachments' bucket are currently removed only through a manual, verified deletion request — they are not automatically deleted when a message or workspace is deleted. |
| R5 | AI drafting prompts & generated replies | public.drafts | Retained for the lifetime of the workspace unless deleted earlier following a verified data deletion request. There is currently no automatic age-based purge. | Workspace/operator deletion, or a verified data deletion request. | Art. 6(1)(f) legitimate interest (quality & abuse detection); Art. 5(1)(e) | Hard delete on verified request; aggregate non-PII metrics retained |
| R5b | AI-derived operator knowledge (saved answers / FAQs) | public.faqs | Retained for the lifetime of the workspace; editable and deletable by the operator at any time in the Brain. No automatic age-based purge. TravelCS does not maintain embeddings or a vector store. | Operator edit/delete, workspace deletion, or a verified data deletion request. | Operator's Art. 6(1)(f) legitimate interest (service knowledge base) | Hard delete of the FAQ row |
| R6 | DSAR requests & audit trail | public.dsar_requests, public.dsar_request_events | 3 years from request closure | Closure date + 3 years | Art. 5(2) accountability; Art. 12(3) demonstrability | Hard delete after retention period; archived export to cold storage if litigation hold applies |
| R7 | Breach incident register | public.breach_incidents, public.breach_incident_events | 5 years from incident closure | Closure date + 5 years | Art. 33(5) breach documentation obligation | Hard delete after retention period |
| R8 | Authentication & security logs | auth audit log, RLS coverage probe rows | Auth logs: 12 months. RLS audit rows: 24 months. | Age-based purge | Art. 32 security of processing; Art. 5(2) accountability | Hard delete; aggregate counters retained |
| R9 | Request / application logs (platform telemetry) | edge logs, request logs | 90 days | Rolling 90-day window | Art. 6(1)(f) legitimate interest (security, debugging) | Automatic rotation |
| R10 | Backups | Managed daily snapshots + point-in-time recovery window | 30 days | Rolling 30-day window | Art. 32(1)(c) availability and resilience | Encrypted snapshots automatically expired |
| R11 | Deleted-operator JSON backups (admin restore window) | public.deleted_operator_backups | 30 days from operator deletion | deleted_at + 30 days (matches R1/R10 backup tail) | Art. 6(1)(c) accountability for admin-initiated erasures; Art. 32(1)(c) availability (short reversibility window for accidental deletion); Art. 5(1)(e) storage limitation | Hard delete of the JSON snapshot row; deletion audited to public.retention_purge_log. DSAR Art. 17 erasure of a customer inside a snapshot is honoured immediately on request, ahead of the 30-day window. |
| R12 | Authenticated user accounts (auth.users) — unassigned or unconfirmed | auth.users | Unconfirmed (email_confirmed_at IS NULL): 24 hours from created_at. Unassigned (no row in user_roles, operator_members or operator_employees): 24 hours from created_at. | Daily pg_cron job 'retention-purge-daily' invokes public.purge_unconfirmed_auth_users(24) and public.purge_unassigned_auth_users(24) inside public.run_retention_purge_daily(); both hard-delete the auth.users row. | Art. 5(1)(c) data minimisation (no lawful processing purpose for an account that never confirmed or was never assigned a role/operator link); Art. 5(1)(f) integrity & confidentiality (minimise dormant attack surface); Art. 32(1)(b) | Hard delete from auth.users; every run audited to public.retention_purge_log under rule_ref='R12-unconfirmed' / 'R12-unassigned' (migrations/069_auth_user_lifecycle.sql). |
Where deletion is manual. Conversation content (public.messages), attachments (public.message_attachments plus the stored files in the message-attachments bucket), AI drafts (public.drafts) and saved answers (public.faqs) are kept for the lifetime of the workspace. No scheduled job deletes them by age today. Deletion happens on workspace deletion (database rows) or through a verified data deletion request via /dsar, which we process within 30 days, subject to applicable legal retention requirements. Stored attachment files are removed only through that verified request.
3. Erasure on request (Art. 17)
A valid erasure request received via /dsar overrides the standard retention period for the categories where erasure is lawful. Records kept under a legal obligation (DSAR audit trail R6, breach register R7, fiscal records) are restricted rather than deleted, with access limited to the DPO until the legal retention period expires.
4. Disposal methods
- Hard delete: row removal from the primary database, cascading to dependent records via foreign-key
ON DELETE CASCADEwhere defined. - Backup expiry: daily encrypted snapshots roll off automatically after the R10 window; no manual restore from expired snapshots is permitted.
- Redaction: where aggregate analytics value remains after the PII window closes, the row is kept but identifying fields are nulled (channel message body, IP address, free-text content).
5. Review
Reviewed at least every 12 months by the DPO and whenever a new processing activity is added to the ROPA. Material changes are notified to operator admins by email and reflected in the privacy notice.
6. Contact
Questions or requests: info@travelcs.ai.