← Back to home · Privacy policy · ROPA · DPA

Data Retention Policy

Version 1.0 — 17 June 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

RefCategorySystem / tableRetention periodDeletion triggerLegal basisDisposal
R1Operator admin & employee accountsauth.users, operator_employees, operator_membersActive life of the account + 30 daysAccount 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 limitationHard delete from primary store; purge from daily backups within 30 days
R1bOperator 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).
R2Landing-page leads (marketing enquiries)public.leads, public.landing_leads12 months from capture12-month rolling window OR earlier opt-out / erasure requestArt. 6(1)(f) legitimate interest (commercial follow-up); Art. 5(1)(e)Monthly automated purge; converted leads migrate to R3 (operator-owned)
R3Booking leads & customer contact detailspublic.booking_leads24 months after last interaction (operator default; configurable per operator)No inbound or outbound message for 24 monthsOperator's Art. 6(1)(b) / (f) basis — TravelCS retains as processor on instructionsSoft-delete + 30-day grace, then hard delete; DSAR erasure honoured immediately
R4Channel message bodies (email, WhatsApp, web chat)public.channel_messages36 months from message timestampRolling 36-month window OR operator account closureOperator's Art. 6(1)(b) basis; Art. 5(1)(c) minimisation enforced via redactionBody purged; minimal metadata (timestamp, channel, direction) kept 12 more months for analytics
R5AI drafting prompts & completionspublic.ai_drafts, ai_employee_runs90 daysDaily age-based purgeArt. 6(1)(f) legitimate interest (quality & abuse detection); Art. 5(1)(e)Hard delete; aggregate non-PII metrics retained indefinitely
R6DSAR requests & audit trailpublic.dsar_requests, public.dsar_request_events3 years from request closureClosure date + 3 yearsArt. 5(2) accountability; Art. 12(3) demonstrabilityHard delete after retention period; archived export to cold storage if litigation hold applies
R7Breach incident registerpublic.breach_incidents, public.breach_incident_events5 years from incident closureClosure date + 5 yearsArt. 33(5) breach documentation obligationHard delete after retention period
R8Authentication & security logsauth audit log, RLS coverage probe rowsAuth logs: 12 months. RLS audit rows: 24 months.Age-based purgeArt. 32 security of processing; Art. 5(2) accountabilityHard delete; aggregate counters retained
R9Request / application logs (platform telemetry)edge logs, request logs90 daysRolling 90-day windowArt. 6(1)(f) legitimate interest (security, debugging)Automatic rotation
R10BackupsManaged daily snapshots + point-in-time recovery window30 daysRolling 30-day windowArt. 32(1)(c) availability and resilienceEncrypted snapshots automatically expired
R11Deleted-operator JSON backups (admin restore window)public.deleted_operator_backups30 days from operator deletiondeleted_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 limitationHard 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.
R12Authenticated user accounts (auth.users) — unassigned or unconfirmedauth.usersUnconfirmed (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).

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

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: dpo@travelcs.ai.