Version 2 · Effective: March 20, 2026 · Published: March 20, 2026
Malcolm
This Data Retention Schedule documents the retention periods for all categories of data processed by the Malcolm platform. It supports compliance with UK GDPR (Article 5(1)(e) — storage limitation), the Data Processing Agreement, and applicable US state privacy laws.
Governing principle: Personal data and customer data are retained only for as long as necessary to fulfil the purposes for which they were collected, or as required by law, contractual obligation, or legitimate business need. Data is deleted or anonymised when the retention period expires.
| Data Category | Description | Retention Period | Trigger for Deletion | Storage Location | Justification |
|---|---|---|---|---|---|
| Tenant schema data | All data within a customer's PostgreSQL schema (deals, portfolio, funds, contacts, interactions, files metadata) | Duration of subscription + 90 days | Subscription termination | AWS RDS (eu-west-2) | DPA Section 8: 90-day deletion window post-termination |
| Tenant files | Documents uploaded by the customer (deal documents, portfolio reports, fund agreements) | Duration of subscription + 90 days | Subscription termination | AWS S3 Files bucket (eu-west-2), KMS-encrypted | Aligned with schema data retention |
| Archived tenant data (soft delete) | pg_dump of tenant schema after soft deletion | 7 years from archival date | Expiration of archival retention | AWS S3 Glacier Deep Archive | Legal/regulatory hold — fund managers may face audit obligations for 7 years |
| WORM vault documents | Capital call notices, distribution notices, legal/compliance documents | 7 years from upload (immutable) | Object Lock expiration (COMPLIANCE mode) | AWS S3 WORM Vault bucket (eu-west-2), Object Lock, KMS-encrypted | Regulatory requirement — immutable record for fund communications and legal documents |
| Data Category | Description | Retention Period | Trigger for Deletion | Storage Location | Justification |
|---|---|---|---|---|---|
| User profile | Name, email, job title, profile photo, preferences | Duration of account + deletion upon request | User deletion request or account deactivation | AWS RDS (eu-west-2) | GDPR Art. 17 — Right to Erasure |
| Authentication data | Password hash, MFA secrets, session tokens | Duration of account | Account deletion | AWS RDS + Redis (eu-west-2) | Operational necessity |
| OAuth tokens | Google, Microsoft, Slack, Notion access/refresh tokens | Until revocation or account deletion | User revokes integration or account deleted | AWS RDS (eu-west-2), encrypted | Data minimisation — deleted immediately on revocation |
| User consent records | Acceptance of Privacy Policy (timestamp, IP, user-agent) | 7 years from acceptance | Statutory limitation period | AWS RDS (eu-west-2) | GDPR Art. 7(1) — demonstrable consent; 6-year limitation + 1 year buffer |
| Tenant consent records | Acceptance of ToS/DPA by org admin (timestamp, IP, user-agent, admin identity) | 7 years from acceptance | Statutory limitation period | AWS RDS (eu-west-2) | Contractual proof of agreement |
| Data Category | Description | Retention Period | Trigger for Deletion | Storage Location | Justification |
|---|---|---|---|---|---|
| LP portal user accounts | Email, name, associated fund interests | Duration of fund + 90 days post-fund termination | Fund manager terminates fund on platform | AWS RDS (eu-west-2) | Aligned with tenant data retention |
| LP portal access logs | Page views, document downloads, e-signatures with IP, user-agent, session | 7 years from event | Expiration | AWS RDS (eu-west-2) | Audit trail for confidential document access — aligned with fund record-keeping requirements |
| Magic link tokens | Signed authentication tokens sent via email | 1 hour | Automatic expiration (TimestampSigner max_age=3600) | In-transit only (not persisted) | Security — minimal exposure window |
| Data Category | Description | Retention Period | Trigger for Deletion | Storage Location | Justification |
|---|---|---|---|---|---|
| AI conversation logs | User prompts, AI responses, tool calls, context used | Duration of subscription + 90 days | Aligned with tenant data deletion | AWS RDS (eu-west-2), within tenant schema | Audit trail for AI-generated outputs; users can review past interactions |
| Data sent to AI providers | Excerpts of customer data sent to Google AI, Anthropic for processing | Not retained by Malcolm post-response; provider retention per provider DPA | N/A — transient | Third-party API (in-transit, TLS) | Data minimisation — not stored locally after response received; providers contractually prohibited from using for training |
| Data Category | Description | Retention Period | Trigger for Deletion | Storage Location | Justification |
|---|---|---|---|---|---|
| AWS CloudTrail logs | All AWS API calls (management + S3 data events) | 90 days hot + 7 years archived | S3 lifecycle policy (90 days → Glacier → 2557-day expiration) | AWS S3 CloudTrail bucket, log validation enabled | Security audit, compliance, incident investigation |
| EKS control plane logs | Kubernetes API, audit, authenticator logs | CloudWatch default retention | CloudWatch log group settings | AWS CloudWatch | Security audit, operational debugging |
| Redis slow logs | Queries exceeding 10ms threshold | 7 days | CloudWatch log group lifecycle | AWS CloudWatch | Performance monitoring |
| RDS PostgreSQL logs | Database query logs, error logs | CloudWatch default retention | CloudWatch log group settings | AWS CloudWatch (exported from RDS) | Debugging, performance analysis |
| Application error logs | Sentry error reports with request context | 90 days | Sentry retention policy | Sentry (third-party) | Debugging, error resolution |
| GuardDuty findings | Threat detection events across 16 AWS regions | 90 days (AWS default) | Automatic expiration | AWS GuardDuty | Threat detection, security monitoring |
| Inspector findings | Vulnerability scan results (EC2, ECR) | Until resolved or 365 days | AWS Inspector lifecycle | AWS Inspector | Vulnerability management |
| Data Category | Description | Retention Period | Trigger for Deletion | Storage Location | Justification |
|---|---|---|---|---|---|
| RDS automated backups (production) | Full database snapshots | 30 days | Rolling window — oldest deleted as new created | AWS RDS (eu-west-2), encrypted | Disaster recovery, SOC 2 alignment |
| RDS automated backups (staging) | Full database snapshots | 7 days | Rolling window | AWS RDS (eu-west-2), encrypted | Development/testing recovery |
| RDS automated backups (shared DB) | Reference database snapshots | 30 days | Rolling window | AWS RDS (eu-west-2), encrypted | Shared data protection |
| EBS snapshots (bastion) | Daily + weekly bastion volume snapshots | Daily: 14 days; Weekly: 90 days | DLM lifecycle policy | AWS EBS Snapshots (eu-west-2), encrypted | Infrastructure recovery |
| S3 incomplete uploads | Multipart upload fragments | 7 days | S3 lifecycle abort rule | AWS S3 Files bucket | Storage cost management |
| S3 staging uploads | Temporary upload staging area | 3 days | S3 lifecycle cleanup rule | AWS S3 Files bucket | Data minimisation — cleanup transient data |
| Data Category | Description | Retention Period | Trigger for Deletion | Storage Location | Justification |
|---|---|---|---|---|---|
| Stripe customer/subscription records | Customer ID, subscription ID, plan, billing status | Duration of subscription + 7 years | Tax/accounting retention requirement | Stripe (third-party) + reference IDs in AWS RDS | Tax record-keeping (HMRC: 6 years + current year) |
| Invoice records | Invoice amounts, dates, line items | 7 years from invoice date | Tax/accounting retention requirement | AWS RDS (eu-west-2) | HMRC/IRS record-keeping requirements |
| AI credit usage | Credit consumption records per tenant | Duration of subscription + 7 years | Aligned with billing records | AWS RDS (eu-west-2) | Billing audit trail |
| Data Category | Description | Retention Period | Trigger for Deletion | Storage Location | Justification |
|---|---|---|---|---|---|
| User sessions | Session ID, cached authentication state | 24 hours from last activity | SESSION_COOKIE_AGE expiration or logout |
AWS ElastiCache (Valkey) + RDS (cached_db backend) | Operational necessity — minimal retention |
| Application cache | Cached query results, computed values | 1 hour default (3600s TTL) | Automatic TTL expiration | AWS ElastiCache (Valkey, eu-west-2) | Performance — transient, no personal data |
| Asset update cache | CRM entity refresh schedules | 2–12 hours depending on entity activity | TTL expiration | AWS ElastiCache (Valkey) | Operational efficiency |
| Task status tracking | Background task progress (uploads, exports, deletions) | 1 hour (3600s TTL) | Automatic TTL expiration | AWS ElastiCache (Valkey) | UX — real-time progress display |
| Presigned URL cache | Temporary S3 download/upload URLs | 1 hour (3600s) | Automatic expiration | In-memory / client-side | Security — minimal exposure window |
Implemented in internal/utils/user_deletion.py:
- Removes user data across all tenant schemas the user belongs to
- Handles M2M relationships, OneToOne, and direct ForeignKey references
- Automated test coverage (internal/tests/test_user_deletion_coverage.py) verifies every User reference across all models is deletion-safe
Implemented in tenants/services/tenant_deletion_service.py:
- Soft delete: Schema archived to S3 Glacier Deep Archive, files migrated to Glacier, schema dropped, tenant deactivated
- Hard delete: All S3 files deleted, schema dropped, tenant record removed
This schedule is reviewed:
| Version | Date | Change |
|---|---|---|
| 1.0 | [Effective date] | Initial publication |
For questions about data retention or to request data deletion:
This Data Retention Schedule was last updated on [effective date].