> ## Documentation Index
> Fetch the complete documentation index at: https://docs.equa.cc/llms.txt
> Use this file to discover all available pages before exploring further.

# Data Retention Policy

> Session lifecycle, soft-delete mechanisms, retention schedules, and data lifecycle management recommendations

# Data Retention Policy

> **Status:** DRAFT
> **Owner:** Engineering / Legal
> **Last Review:** 2026-05-03
> **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  | Yes      | All persisted data and session store; exact managed provider is still under deployment-audit verification |
| 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.

<Warning>
  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.
</Warning>

### 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            |

<Warning>
  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).
</Warning>

### 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                                                    |

<Warning>
  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).
</Warning>

### 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

1. **Formalize this document** as the official data retention policy
2. **Classify all data tables** into the retention tiers above
3. **Document legal holds** -- process for suspending retention-based deletion when litigation or regulatory investigation is anticipated

### Phase 2: Automated Lifecycle Management

1. **Retention tags** -- Add a `retentionTier` and `retentionExpiry` metadata column to key tables or a central retention registry
2. **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
3. **Soft-delete cleanup** -- Add retention expiry tracking to soft-deleted records so they are eventually purged after regulatory retention periods expire
4. **Transient data cleanup** -- Implement cleanup jobs for `EmailVerifications`, `Onetimecodes`, and `onboarding_sessions`

### Phase 3: User-Facing Data Lifecycle

1. **Data export** -- Allow users to export their data before account closure (see [Data Privacy and GDPR](/compliance/data-privacy-and-gdpr))
2. **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
3. **Retention dashboard** -- Admin view showing data volumes by retention tier and upcoming purge schedules

### Phase 4: Compliance Reporting

1. **Retention compliance report** -- Show adherence to retention schedules
2. **Data inventory** -- Automated discovery and classification of all stored PII
3. **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 |
