Data Retention Policy
Status: DRAFT
Owner: Engineering / Legal
Last Review: 2026-02-21
Applicable Standards: GDPR (Art. 5(1)(e), Art. 17) / SOC 2 (P4.2, CC6.5) / IRS Record Retention / SEC Rule 17a-4
1. Purpose
This document describes Equa’s current data retention practices, identifies gaps, and recommends a formal data lifecycle management framework. An equity management platform must balance GDPR data minimization with regulatory retention obligations for securities and tax records.
2. Scope
| Component | In Scope | Notes |
|---|
| equa-server | Yes | Session lifecycle, soft delete logic, entity retention |
| PostgreSQL (Cloud SQL) | Yes | All persisted data, session store |
| AWS S3 | Yes | Document uploads, certificates |
| equa-web | Partial | Client-side session cookies, local storage |
3. Current Retention Implementation
3.1 Session Retention
Source: equa-server/modules/auth/src/sessions.ts, equa-server/modules/auth/src/lib/session-cleaning.ts
| Parameter | Value | Source |
|---|
| Session store | PostgreSQL via TypeORMSessionStore | equa-server/modules/auth/src/sessions.ts |
| Max age | 42 minutes rolling (API_SESSION_MAX_AGE, default: 2,520,000ms) | equa-server/modules/auth/src/sessions.ts |
| Rolling | true — expiry resets on each request | equa-server/modules/auth/src/sessions.ts |
| Cleanup | Cron job removes expired records based on expires column | equa-server/modules/auth/src/lib/session-cleaning.ts |
| On logout | Session record is destroyed | Application logic |
Sessions are one of the few data types with an explicit, automated retention and cleanup policy.
3.2 Magic Link Retention
Source: equa-server/modules/auth/src/magic-link.ts
| Parameter | Value |
|---|
| Expiry | 15 minutes (MAGIC_LINK_EXPIRY_MINUTES = 15) |
| Cleanup | cleanupExpiredMagicLinks() deletes records where expiresAt < now |
| Fields stored | token, email, expiresAt, used |
Magic links are the second data type with automated lifecycle management. The cleanup function is called periodically to remove expired tokens.
3.3 Onboarding Session Retention
Source: equa-server/modules/persistence/lab/sql/migrations/2.33.0-onboarding-tables.sql
| Parameter | Value |
|---|
| Expiry | 24 hours (expires_at DEFAULT NOW() + INTERVAL '24 hours') |
| Related tables | onboarding_files (CASCADE on delete), onboarding_questions (CASCADE on delete) |
| Fields stored | email, initial_prompt, analysis_result, file_analysis_results |
The onboarding_sessions table has an expires_at column with a 24-hour default, and child tables (onboarding_files, onboarding_questions) cascade on delete.
No automated cleanup job for expired onboarding sessions was found in the codebase. The expires_at column exists but may not be actively enforced by a purge job.Recommendation: Implement a scheduled cleanup job (similar to cleanupExpiredMagicLinks) that deletes onboarding sessions past their expires_at timestamp.
3.4 Email Verification Retention
Source: equa-server/modules/persistence/src/schema.ts (EmailVerifications entity, line 799)
| Parameter | Value |
|---|
| Fields | user (UUID), code |
| TTL | None documented |
| Cleanup | None found |
The EmailVerifications entity stores verification codes with no documented TTL or cleanup mechanism. Expired verification codes accumulate indefinitely.Recommendation: Add an expiresAt column and a cleanup job to purge verification codes after a reasonable period (e.g., 24 hours).
3.5 One-Time Code Retention
Source: equa-server/modules/persistence/src/schema.ts (Onetimecodes entity, line 835)
| Parameter | Value |
|---|
| Fields | user (UUID), code, available (boolean, default: true) |
| TTL | None — no expiry column exists |
| State management | available boolean toggled to false after use |
| Cleanup | None found |
The Onetimecodes entity has an available boolean to mark codes as used, but no expiry column or cleanup mechanism. Used one-time codes remain in the database indefinitely.Recommendation: Add an expiresAt column and a cleanup job, or delete used codes after a short retention period (e.g., 7 days).
3.6 Soft Delete Mechanism
Source: equa-server/modules/common/src/lib/utility.ts (line 37)
The platform uses a deleted boolean flag on entities that extend the CreatedModifiedDeleted base class. This is the primary soft-delete mechanism — there is no separate DeletedRecords snapshot table.
Base class definition:
abstract class CreatedModifiedDeleted extends CreatedModified {
@Column({ default: false })
deleted: boolean = false
}
Entities using CreatedModifiedDeleted (soft-deletable):
| Entity | Source Line | Data Type |
|---|
Users | 410 | User accounts |
Members | 892 | Organization members (equity holders) |
Organizations | 1207 | Company records |
TaxIds | 871 | Tax identification numbers |
Tasks | 847 | Workflow tasks |
TasksExerciseOption | 859 | Option exercise tasks |
Waitlists | 398 | Waitlist entries |
RegisteredAgents | 1363 | Registered agents |
OrganizationTemplates | 1405 | Document templates |
Additionally, some hashed entities use a standalone deleted: boolean column (not via the base class):
| Entity | Source Line | Notes |
|---|
SecurityTypes | 925 (line 984) | deleted column with doNotHash comment |
Authorizations | 1378 (line 1400) | deleted column with doNotHash comment |
Strengths:
- Preserves data for regulatory retention requirements
- Simple, consistent pattern across entities
- Timestamps available via
created and modified from the base class
Limitations:
- No automatic purge schedule — soft-deleted records accumulate indefinitely
- No distinction between regulatory-hold deletions and routine cleanup
- No
deletedBy field to track who performed the deletion
- No
deletedAt timestamp separate from modified (the modified column updates on soft delete, but is ambiguous)
- No mechanism to permanently purge records after retention periods expire
4. Regulatory Retention Requirements
4.1 Securities Records
| Record Type | Retention Requirement | Basis |
|---|
| Stock transfer records | Permanent (while company exists) | State corporation law |
| Equity grant agreements | 7 years minimum after termination/expiry | SEC Rule 17a-4 guidance |
| Board resolutions (equity-related) | Permanent | Corporate governance |
| Cap table snapshots | 7 years minimum | Securities law, audit requirements |
| 409A valuation reports | 7 years after the later of grant exercise or expiry | IRC Section 409A |
4.2 Tax Records
| Record Type | Retention Requirement | Basis |
|---|
| Form 3921 (ISO exercises) | 7 years | IRS requirements |
| Form 1099 data | 7 years | IRS requirements |
| Tax ID records (SSN/EIN) | Duration of relationship + 7 years | IRS requirements |
4.3 General PII
| Record Type | Retention Requirement | Basis |
|---|
| User account data | Duration of account + reasonable period | GDPR Article 5(1)(e) |
| Contact information | Duration of relationship | GDPR data minimization |
| Activity / audit logs | 3—7 years depending on content | Varies by regulation |
| Authentication logs | 1 year minimum | Security best practices |
5. Recommended Retention Schedule
Tier 1: Permanent Retention
Records that must be retained as long as the organization exists on the platform:
- Stock transfer ledger entries (
Shareholdings, Transactions)
- Share class definitions (
SecurityTypes, SecurityTypeShares)
- Board resolution records (
Authorizations)
- Certificate issuance and cancellation records (
Shareholdings)
- Operating agreements (
OperatingAgreements)
Tier 2: Long-Term Retention (7 years)
Records retained for 7 years after the relevant event:
- Equity grant agreements (
Options, Plans) — 7 years after termination/expiry/exercise
- 409A valuation reports (
Files in data room) — 7 years after the later of grant exercise or expiry
- Tax filing data (
TaxIds, Form 3921/1099 records)
- Cap table snapshots (
Holdings) — 7 years from snapshot date
- Financial transaction records (
Transactions)
Tier 3: Medium-Term Retention (3 years)
Records retained for 3 years after creation or last activity:
- Audit log entries (
EventLogs, non-financial)
- User activity logs
- Email delivery records
- Task completion records (
Tasks)
Tier 4: Short-Term Retention (1 year)
Records retained for 1 year:
- Authentication logs (login/logout events)
- API access logs
- Session records beyond the 29-day active window
- Failed authentication attempts
Tier 5: Transient (30 days or less)
Records that should be purged regularly:
- Expired session data (currently 42 minutes — implemented)
- Magic link tokens (currently 15 minutes — implemented)
- Onboarding sessions (24-hour
expires_at — schema exists, cleanup TBD)
- Email verification codes (no expiry — gap)
- One-time codes (no expiry — gap)
- Temporary upload staging files
- Cache entries
6. Implementation Recommendations
Phase 1: Policy Documentation
- Formalize this document as the official data retention policy
- Classify all data tables into the retention tiers above
- Document legal holds — process for suspending retention-based deletion when litigation or regulatory investigation is anticipated
Phase 2: Automated Lifecycle Management
- Retention tags — Add a
retentionTier and retentionExpiry metadata column to key tables or a central retention registry
- Purge jobs — Implement scheduled jobs that:
- Identify records past their retention expiry
- Check for legal holds before purging
- Permanently delete (not soft-delete) expired records
- Log all purge actions to the audit trail
- Soft-delete cleanup — Add retention expiry tracking to soft-deleted records so they are eventually purged after regulatory retention periods expire
- Transient data cleanup — Implement cleanup jobs for
EmailVerifications, Onetimecodes, and onboarding_sessions
Phase 3: User-Facing Data Lifecycle
- Data export — Allow users to export their data before account closure (see Data Privacy and GDPR)
- Account deletion — Implement a full account deletion workflow that:
- Exports user data (for portability)
- Soft-deletes user records with appropriate retention tags
- Anonymizes audit trail entries after retention period
- Permanently purges all PII after regulatory retention periods expire
- Retention dashboard — Admin view showing data volumes by retention tier and upcoming purge schedules
Phase 4: Compliance Reporting
- Retention compliance report — Show adherence to retention schedules
- Data inventory — Automated discovery and classification of all stored PII
- Purge audit log — Tamper-evident record of all data purges for regulatory review
7. Regulatory References
| Standard | Requirement | Current Status |
|---|
| GDPR Art. 5(1)(e) | Storage limitation — personal data kept no longer than necessary | Gap — no automated retention enforcement; soft-deleted records retained indefinitely |
| GDPR Art. 17 | Right to erasure | Partial — soft delete exists but no permanent purge after retention period |
| SOC 2 P4.2 | Data disposal when no longer needed | Gap — no formal disposal procedures |
| SOC 2 CC6.5 | Disposal of confidential information | Gap — no documented disposal process |
| IRS (IRC 6001) | 7-year retention for tax records | Implemented — data retained indefinitely (exceeds requirement) |
| SEC Rule 17a-4 | 7-year retention for securities records | Implemented — data retained indefinitely (exceeds requirement) |
8. Revision History
| Date | Version | Author | Changes |
|---|
| 2026-02-21 | 0.1 | Agent (Phase 5 Session A) | Initial draft |
| 2026-02-21 | 0.2 | Agent (Phase 5 Session B) | Template alignment, corrected soft-delete mechanism (boolean flag not snapshot table), added magic link/onboarding/verification/one-time code lifecycle items, entity-by-entity soft-delete inventory, regulatory references table |