# ByteLyst — End-to-End Encryption Implementation Roadmap

> **Purpose:** Phased implementation plan for encryption across the ByteLyst ecosystem.  
> **Status:** Roadmap — not yet started  
> **Author:** AI Architecture Review  
> **Last updated:** 2026-03-21  
> **Design doc:** [`END_TO_END_ENCRYPTION_DESIGN.md`](END_TO_END_ENCRYPTION_DESIGN.md)

---

## Overview

This roadmap implements the tiered encryption strategy defined in the design document. Work is organized into 6 sprints across 3 phases, estimated at **12-16 weeks** total elapsed time.

### Phase Summary

| Phase                          | Sprints    | Duration  | Deliverable                                                                           |
| ------------------------------ | ---------- | --------- | ------------------------------------------------------------------------------------- |
| **Phase 1: Foundation**        | Sprint 1-2 | 4-5 weeks | `@bytelyst/field-encrypt` package + AKV infrastructure + first 2 product integrations |
| **Phase 2: Ecosystem Rollout** | Sprint 3-4 | 4-5 weeks | All 10 product backends encrypted + native SDK components + web secure storage        |
| **Phase 3: Advanced**          | Sprint 5-6 | 4-6 weeks | True E2EE for JarvisJr/NoteLett + SQLite encryption + blob CMK + audit tooling        |

### Milestone Timeline

```
Week 1-2     Week 3-4     Week 5-6     Week 7-8     Week 9-10    Week 11-14
┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────┐
│ Sprint 1 │ │ Sprint 2 │ │ Sprint 3 │ │ Sprint 4 │ │ Sprint 5 │ │   Sprint 6   │
│ Package + │ │ LysnrAI +│ │ 4 more   │ │ Native   │ │ E2EE     │ │   Audit +    │
│ AKV infra │ │ JarvisJr │ │ products │ │ SDKs +   │ │ private  │ │   polish +   │
│          │ │          │ │          │ │ web      │ │ vaults   │ │   docs       │
└──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────┘ └──────────────┘
  Phase 1       Phase 1      Phase 2      Phase 2      Phase 3       Phase 3
```

---

## Phase 1: Foundation (Weeks 1-5)

### Sprint 1 — `@bytelyst/field-encrypt` Package + AKV Infrastructure (Week 1-2)

**Goal:** Ship the shared encryption package and configure Azure Key Vault for key management.

#### 1.1 Azure Key Vault Infrastructure

- [ ] **1.1.1** Enable RBAC mode on `kv-mywisprai` vault (`enableRbacAuthorization=true`)
  - Assign `Key Vault Crypto Officer` to deployer user
  - Assign `Key Vault Crypto User` to service managed identities (when deployed)
  - **File:** Azure Portal / `az keyvault update`
  - **Risk:** Breaking change — all existing access policies stop working. Must reassign as RBAC roles simultaneously.
  - **Rollback:** `az keyvault update --enable-rbac-authorization false` + re-create access policies

- [ ] **1.1.2** Create 10 Master Encryption Keys (MEKs) in AKV

  ```
  lysnr-mek, mindlyst-mek, jarvisjr-mek, chronomind-mek,
  nomgap-mek, peakpulse-mek, flowmonk-mek, actiontrail-mek,
  notelett-mek, localmemgpt-mek
  ```

  - RSA 4096-bit, `wrapKey` + `unwrapKey` operations enabled
  - **Script:** `scripts/create-encryption-keys.sh`

- [ ] **1.1.3** Add new env vars to `.env.example` and AKV secrets doc

  ```
  AZURE_KEYVAULT_URL=https://kv-mywisprai.vault.azure.net
  FIELD_ENCRYPT_KEY_PROVIDER=akv    # 'akv' | 'env' | 'memory'
  FIELD_ENCRYPT_MEK_NAME=lysnr-mek  # product-specific
  ```

  - **Files:** `.env.example`, `docs/devops/ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md`

#### 1.2 `@bytelyst/field-encrypt` Package

- [ ] **1.2.1** Create package scaffold

  ```
  packages/field-encrypt/
  ├── src/
  │   ├── index.ts
  │   ├── types.ts
  │   ├── aes-gcm.ts
  │   ├── envelope.ts
  │   ├── key-provider-akv.ts
  │   ├── key-provider-env.ts
  │   ├── key-provider-memory.ts
  │   ├── key-cache.ts
  │   ├── migration.ts
  │   └── index.test.ts
  ├── package.json
  └── tsconfig.json
  ```

  - **Dependencies:** `@azure/keyvault-keys`, `@azure/identity` (peer), `zod` (peer)
  - **Dev dependencies:** `vitest`

- [ ] **1.2.2** Implement core AES-256-GCM encrypt/decrypt
  - `aes-gcm.ts` — `encryptField()`, `decryptField()` using `node:crypto`
  - Input: plaintext string + key buffer + optional AAD
  - Output: `EncryptedField` object `{ __encrypted, v, alg, ct, iv, tag, dekId }`
  - **Tests:** encrypt → decrypt roundtrip, invalid authTag rejection, empty string, unicode, large payload (1 MB)

- [ ] **1.2.3** Implement envelope encryption (DEK management)
  - `envelope.ts` — `generateDek()`, `wrapDek()`, `unwrapDek()`
  - DEK: 32-byte random AES key, identified by `dek_{userId}_{context}`
  - Wrap: RSA-OAEP with MEK in AKV
  - Stored: `{ dekId, wrappedKey, mekVersion, createdAt }` in a `_encryption_keys` Cosmos container
  - **Tests:** generate → wrap → unwrap roundtrip, MEK version tracking

- [ ] **1.2.4** Implement key providers
  - `key-provider-akv.ts` — Production: `@azure/keyvault-keys` `CryptographyClient`
  - `key-provider-env.ts` — Dev/staging: raw hex key from `FIELD_ENCRYPT_KEY` env var (like current MFA pattern)
  - `key-provider-memory.ts` — Unit tests: random in-memory key, no external deps
  - **Tests:** provider interface contract tests for each

- [ ] **1.2.5** Implement DEK cache
  - `key-cache.ts` — In-memory LRU cache with configurable TTL (default 15 min)
  - Cache key: `dekId`, value: unwrapped DEK buffer
  - Auto-evict on TTL expiry, manual `invalidate(dekId)` for rotation
  - **Tests:** cache hit/miss, TTL expiry, manual invalidation, max size eviction

- [ ] **1.2.6** Implement `createFieldEncryptor()` factory
  - Wires key provider + cache + AES-GCM
  - Public API: `encrypt()`, `decrypt()`, `encryptBatch()`, `decryptBatch()`, `isEncrypted()`
  - **Tests:** full integration test with memory provider

- [ ] **1.2.7** Implement migration helpers
  - `migration.ts` — `migrateField()`: read plaintext, encrypt, write back (idempotent)
  - Supports batch size, dry run, progress callback
  - Detects already-encrypted fields via `__encrypted` sentinel
  - **Tests:** migrate plaintext → encrypted, skip already-encrypted, dry run mode

- [ ] **1.2.8** Add `isEncrypted()` type guard
  - Exported utility for repositories to detect encrypted vs plaintext during migration period
  - **Tests:** true for EncryptedField, false for string, false for null/undefined

**Sprint 1 deliverable:** `@bytelyst/field-encrypt` package with all 3 key providers, ~30 tests, `pnpm build && pnpm test` passing.

**Commit:** `feat(field-encrypt): create @bytelyst/field-encrypt package with AES-256-GCM envelope encryption`

---

### Sprint 2 — First Product Integrations: LysnrAI + JarvisJr (Week 3-4)

**Goal:** Encrypt the highest-sensitivity fields in 2 products. Validate the pattern end-to-end.

#### 2.1 LysnrAI Backend (port 4015)

- [ ] **2.1.1** Add `@bytelyst/field-encrypt` dependency to `backend/package.json`

  ```json
  "@bytelyst/field-encrypt": "file:../../learning_ai_common_plat/packages/field-encrypt"
  ```

- [ ] **2.1.2** Create `backend/src/lib/field-encrypt.ts` — service-level encryptor singleton

  ```typescript
  import { createFieldEncryptor } from '@bytelyst/field-encrypt';
  import { config } from './config.js';

  export const encryptor = createFieldEncryptor({
    keyProvider: config.FIELD_ENCRYPT_KEY_PROVIDER ?? 'memory',
    mekName: 'lysnr-mek',
    keyVaultUrl: config.AZURE_KEYVAULT_URL,
  });
  ```

- [ ] **2.1.3** Encrypt `rawText` and `cleanedText` in transcripts module
  - `repository.ts`: encrypt on `create()`, decrypt on `findById()` and `findByUserId()`
  - Keep field names but value changes from string to EncryptedField
  - **Migration:** Add `POST /api/admin/migrate-encryption` endpoint (admin-only) that batch-encrypts existing plaintext

- [ ] **2.1.4** Update config schema with encryption env vars

  ```typescript
  FIELD_ENCRYPT_KEY_PROVIDER: z.enum(['akv', 'env', 'memory']).default('memory'),
  FIELD_ENCRYPT_KEY: z.string().optional(), // only for 'env' provider
  AZURE_KEYVAULT_URL: z.string().url().optional(),
  ```

- [ ] **2.1.5** Update tests — ensure existing tests pass with memory provider (no env vars needed)

**Commit:** `feat(lysnrai): encrypt rawText and cleanedText fields with @bytelyst/field-encrypt`

#### 2.2 JarvisJr Backend (port 4012)

- [ ] **2.2.1** Add `@bytelyst/field-encrypt` dependency

- [ ] **2.2.2** Create `backend/src/lib/field-encrypt.ts` encryptor singleton

- [ ] **2.2.3** Encrypt fields in jarvis-sessions module
  - `transcript` field — `Array<{role,content,ts}>`, JSON-serialize before encrypting as single EncryptedField
  - `coachingNotes` field — `string[]`, JSON-serialize before encrypting as single EncryptedField
  - **Note:** Array fields use the JSON-serialize → encrypt → store pattern (see design doc §4.5)

- [ ] **2.2.4** Encrypt fields in jarvis-memory module
  - `content` field — per-agent persistent memory entries

- [ ] **2.2.5** Update config + tests

**Commit:** `feat(jarvisjr): encrypt session transcripts, coaching notes, and agent memory`

#### 2.3 Refactor MFA to Use Shared Package

- [ ] **2.3.1** Migrate `platform-service/src/modules/auth/mfa/repository.ts` from inline AES-256-GCM to `@bytelyst/field-encrypt`
  - Replace `encryptSecret()` / `decryptSecret()` with `encryptor.encrypt()` / `encryptor.decrypt()`
  - Remove inline `createCipheriv` / `createDecipheriv` code
  - Keep `AUTH_TOTP_ENCRYPTION_KEY` as `env` key provider for backward compatibility
  - **Tests:** All existing MFA tests must still pass

**Commit:** `refactor(auth): migrate MFA encryption to @bytelyst/field-encrypt`

**Sprint 2 deliverable:** 2 product backends fully encrypted, MFA migrated, all tests green.

---

## Phase 2: Ecosystem Rollout (Weeks 5-10)

### Sprint 3 — Four More Product Backends (Week 5-6)

**Goal:** Encrypt sensitive fields in NoteLett, MindLyst, NomGap, and ActionTrail.

#### 3.1 NoteLett Backend (port 4016)

- [ ] **3.1.1** Add dependency + create encryptor singleton
- [ ] **3.1.2** Encrypt `body` field in notes module
- [ ] **3.1.3** Encrypt `content` field in note-artifacts module
- [ ] **3.1.4** Update MCP tools to decrypt before processing
- [ ] **3.1.5** Update tests

**Commit:** `feat(notelett): encrypt note body and artifact content`

#### 3.2 MindLyst Backend (port 4014)

- [ ] **3.2.1** Add dependency + create encryptor singleton
- [ ] **3.2.2** Encrypt `content` and `voiceTranscriptText` in memory_items module
- [ ] **3.2.3** Encrypt array fields in reflections module
  - `repeatedThemes` (string[]), `suggestedAdjustments` (string[]), `vsLastWeek.summary` (string)
  - Array fields: JSON-serialize → encrypt → store as single EncryptedField each
- [ ] **3.2.4** Update tests

**Commit:** `feat(mindlyst): encrypt memory content, voice transcripts, and reflections`

#### 3.3 NomGap Backend (port 4013)

- [ ] **3.3.1** Add dependency + create encryptor singleton
- [ ] **3.3.2** Encrypt `notes` field in meal-logs module
- [ ] **3.3.3** Encrypt `notes` field in fasting-sessions module (including `moodCheckins[].notes`)
- [ ] **3.3.4** Encrypt `notes` field in weight-log module
- [ ] **3.3.5** Update tests

**Commit:** `feat(nomgap): encrypt notes fields across meal-log, fasting-sessions, and weight-log`

#### 3.4 ActionTrail Backend (port 4018)

- [ ] **3.4.1** Add dependency + create encryptor singleton
- [ ] **3.4.2** Encrypt `before` and `after` fields in actions module
- [ ] **3.4.3** Encrypt `beforeState` and `afterState` fields in reverts module
- [ ] **3.4.4** Update tests

**Commit:** `feat(actiontrail): encrypt action and revert snapshots`

#### 3.5 Remaining Backends (Low Priority — Defer or Skip)

| Product                | Backend Port        | Encrypted Fields                    | Decision |
| ---------------------- | ------------------- | ----------------------------------- | -------- |
| **FlowMonk** (4017)    | `tasks.description` | Defer to Sprint 4 — low sensitivity |
| **ChronoMind** (4011)  | None                | Skip — timer configs not sensitive  |
| **PeakPulse** (4010)   | None                | Skip — GPS/stats not sensitive      |
| **LocalMemGPT** (4019) | `messages.content`  | Sprint 5 (SQLite-specific approach) |

**Sprint 3 deliverable:** 6 product backends encrypted (LysnrAI, JarvisJr, NoteLett, MindLyst, NomGap, ActionTrail).

---

### Sprint 4 — Native SDKs + Web Secure Storage + FlowMonk (Week 7-8)

**Goal:** Add client-side encryption primitives to all SDKs. Secure web localStorage.

#### 4.1 Swift Platform SDK — `BLFieldEncrypt`

- [ ] **4.1.1** Create `Sources/BLFieldEncrypt.swift` in `packages/swift-platform-sdk/`

  ```swift
  import CryptoKit

  public struct BLFieldEncrypt {
      /// Encrypt a string field with AES-256-GCM
      public static func encrypt(_ plaintext: String, key: SymmetricKey) -> EncryptedField
      /// Decrypt an encrypted field
      public static func decrypt(_ field: EncryptedField, key: SymmetricKey) -> String?
      /// Check if a JSON value is an encrypted field
      public static func isEncrypted(_ value: Any) -> Bool
  }

  public struct EncryptedField: Codable {
      public let __encrypted: Bool  // always true
      public let v: Int             // version
      public let alg: String        // "aes-256-gcm"
      public let ct: String         // ciphertext (base64)
      public let iv: String         // IV (hex)
      public let tag: String        // auth tag (hex)
      public let dekId: String      // DEK identifier
  }
  ```

- [ ] **4.1.2** Key derivation from Keychain-stored secret
- [ ] **4.1.3** Unit tests (XCTest)

**Commit:** `feat(swift-sdk): add BLFieldEncrypt for client-side AES-256-GCM encryption`

#### 4.2 Kotlin Platform SDK — `BLFieldEncrypt`

- [ ] **4.2.1** Create `src/main/.../BLFieldEncrypt.kt` in `packages/kotlin-platform-sdk/`
  ```kotlin
  object BLFieldEncrypt {
      fun encrypt(plaintext: String, key: SecretKeySpec): EncryptedField
      fun decrypt(field: EncryptedField, key: SecretKeySpec): String?
      fun isEncrypted(value: Any?): Boolean
  }
  ```
- [ ] **4.2.2** Key derivation from BLSecureStore
- [ ] **4.2.3** Unit tests (JUnit5)

**Commit:** `feat(kotlin-sdk): add BLFieldEncrypt for client-side AES-256-GCM encryption`

#### 4.3 TypeScript Client Package — `@bytelyst/client-encrypt`

- [ ] **4.3.1** Create `packages/client-encrypt/` for browser + React Native
  ```typescript
  // Uses Web Crypto API (SubtleCrypto) — works in browsers and React Native
  export function encryptField(plaintext: string, key: CryptoKey): Promise<EncryptedField>;
  export function decryptField(field: EncryptedField, key: CryptoKey): Promise<string>;
  export function deriveKey(passphrase: string, salt: Uint8Array): Promise<CryptoKey>;
  ```
- [ ] **4.3.2** PBKDF2 key derivation for web (600,000 iterations)
- [ ] **4.3.3** Tests with vitest + happy-dom

**Commit:** `feat(client-encrypt): create @bytelyst/client-encrypt for browser/RN encryption`

#### 4.4 Web Secure Storage

- [ ] **4.4.1** Create `@bytelyst/secure-storage-web` package
  - IndexedDB-backed storage with `SubtleCrypto` non-extractable AES key
  - API: `secureGet(key)`, `secureSet(key, value)`, `secureDelete(key)`, `secureClear()`
  - Key is generated once, stored as non-extractable CryptoKey in IndexedDB
  - Falls back to `localStorage` if `SubtleCrypto` unavailable

- [ ] **4.4.2** Migrate auth tokens from `localStorage` to secure storage in all web apps
  - Update `@bytelyst/auth-client` to use secure storage
  - **Products affected:** All 7 web dashboards/apps

**Commit:** `feat(secure-storage-web): IndexedDB + SubtleCrypto encrypted storage for web`

#### 4.5 FlowMonk Backend (port 4017)

- [ ] **4.5.1** Add dependency + encrypt `tasks.description` field
- [ ] **4.5.2** Update tests

**Commit:** `feat(flowmonk): encrypt task notes`

**Sprint 4 deliverable:** All native SDKs have encryption primitives. Web secure storage. 7 backends encrypted.

---

## Phase 3: Advanced Encryption (Weeks 9-14)

### Sprint 5 — True E2EE Private Vaults + SQLite Encryption (Week 9-10)

**Goal:** Implement zero-knowledge encryption for opt-in private spaces in JarvisJr and NoteLett. Encrypt LocalMemGPT SQLite.

#### 5.1 E2EE Key Management Infrastructure

- [ ] **5.1.1** Design E2EE key exchange protocol
  - User generates X25519 keypair on device
  - Public key uploaded to platform-service `user_public_keys` container
  - Private key stored in Keychain (iOS/Mac) / Keystore (Android) / derived from passphrase (Web)
  - Recovery: 12-word BIP-39 mnemonic → seed → keypair

- [ ] **5.1.2** Create `@bytelyst/e2ee-core` package

  ```typescript
  export function generateKeypair(): { publicKey: Uint8Array; privateKey: Uint8Array };
  export function generateRecoveryPhrase(): string; // 12 BIP-39 words
  export function keypairFromRecovery(phrase: string): { publicKey; privateKey };
  export function encryptForUser(
    plaintext: string,
    recipientPublicKey: Uint8Array
  ): EncryptedPayload;
  export function decryptForUser(payload: EncryptedPayload, privateKey: Uint8Array): string;
  ```

  - Uses X25519 for key agreement, HKDF-SHA256 for derivation, AES-256-GCM for encryption
  - **Dependencies:** `@noble/curves` (X25519), `@noble/hashes` (HKDF, SHA256)
  - **Tests:** ~20 tests

- [ ] **5.1.3** Add `user_public_keys` container to platform-service
  - Schema: `{ id, userId, productId, publicKey (base64), deviceId, createdAt }`
  - Partition key: `/userId`
  - Routes: `POST /auth/e2ee/register-key`, `GET /auth/e2ee/public-key/:userId`

- [ ] **5.1.4** Multi-device key sync
  - iOS: Share private key via iCloud Keychain (requires entitlement)
  - Android: Share via Google Backup (EncryptedSharedPreferences)
  - Cross-platform: QR code containing encrypted private key (encrypted with passphrase)

**Commit:** `feat(e2ee): create @bytelyst/e2ee-core + platform key registration`

#### 5.2 JarvisJr E2EE Private Agents

- [ ] **5.2.1** Add `isPrivate` boolean field to agent config
  - When `true`, all session transcripts and memory for this agent are E2EE
  - Server stores only ciphertext — cannot decrypt
  - AI features (PromptBuilder, memory retrieval) disabled for private agents
  - UI shows "Private Agent" badge + "AI features unavailable" warning

- [ ] **5.2.2** Client-side encrypt before API calls (iOS + Web)
  - Session transcript → `e2eeCore.encryptForUser(transcript, userPublicKey)`
  - Memory content → `e2eeCore.encryptForUser(content, userPublicKey)`
  - Client-side decrypt after reads

- [ ] **5.2.3** Update JarvisJr web + iOS to handle E2EE toggle

**Commit:** `feat(jarvisjr): E2EE private agents with zero-knowledge encryption`

#### 5.3 NoteLett E2EE Private Workspaces

- [ ] **5.3.1** Add `isEncrypted` boolean field to workspace config
  - When `true`, all notes in workspace are E2EE
  - MCP tools return encrypted content (agent cannot read)
  - Search disabled for encrypted workspaces

- [ ] **5.3.2** Client-side encrypt before API calls (Web + Mobile)
- [ ] **5.3.3** Update UI with "Encrypted Workspace" badge + trade-off warnings

**Commit:** `feat(notelett): E2EE private workspaces with zero-knowledge encryption`

#### 5.4 LocalMemGPT SQLite Encryption

- [ ] **5.4.1** Evaluate `better-sqlite3-sqlcipher` vs application-level encryption
  - If SQLCipher: swap `better-sqlite3` → `better-sqlite3-sqlcipher`, add `PRAGMA key`
  - If app-level: encrypt `content` column via `@bytelyst/field-encrypt` (env provider)

- [ ] **5.4.2** Implement chosen approach
- [ ] **5.4.3** Handle FTS5 index (see design doc §7.2)
- [ ] **5.4.4** Migration: encrypt existing unencrypted databases on first startup

**Commit:** `feat(localmemgpt): encrypt SQLite message content`

**Sprint 5 deliverable:** E2EE private vaults for JarvisJr + NoteLett. SQLite encryption for LocalMemGPT.

---

### Sprint 6 — Blob CMK + Audit Tooling + Documentation (Week 11-14)

**Goal:** Complete the encryption story with blob storage, monitoring, migration tooling, and docs.

#### 6.1 Azure Blob Storage Customer-Managed Key (CMK)

- [ ] **6.1.1** Create `bytelyst-blob-mek` RSA key in AKV
- [ ] **6.1.2** Configure `bytelystblobs` storage account to use CMK from AKV
  - Azure Portal → Storage account → Encryption → Customer-managed keys
  - Select `bytelyst-blob-mek` from `kv-mywisprai`
- [ ] **6.1.3** Verify all blob operations still work (upload, download, SAS tokens)
- [ ] **6.1.4** Update `AZURE_RESOURCE_INVENTORY.md`

**Commit:** `feat(infra): enable customer-managed encryption key for Azure Blob Storage`

#### 6.2 Encryption Migration CLI

- [ ] **6.2.1** Create `scripts/encrypt-migrate.ts` — CLI tool for batch encrypting existing plaintext

  ```bash
  npx tsx scripts/encrypt-migrate.ts \
    --product lysnrai \
    --container transcripts \
    --field transcriptText \
    --partition-key /userId \
    --batch-size 100 \
    --dry-run
  ```

  - Uses `@bytelyst/field-encrypt` migration helpers
  - Progress bar, resumable (tracks last processed ID)
  - Dry run mode (report count without modifying)

- [ ] **6.2.2** Create per-product migration scripts
  ```
  scripts/migrations/
  ├── encrypt-lysnrai.sh
  ├── encrypt-jarvisjr.sh
  ├── encrypt-notelett.sh
  ├── encrypt-mindlyst.sh
  ├── encrypt-nomgap.sh
  ├── encrypt-actiontrail.sh
  ├── encrypt-flowmonk.sh
  └── encrypt-localmemgpt.sh
  ```

**Commit:** `feat(devops): encryption migration CLI and per-product migration scripts`

#### 6.3 Monitoring & Audit

- [ ] **6.3.1** Add encryption metrics to telemetry
  - `field_encrypt_count` — encryptions performed
  - `field_decrypt_count` — decryptions performed
  - `dek_cache_hit_rate` — DEK cache efficiency
  - `dek_unwrap_latency_ms` — AKV round-trip time
  - `migration_progress` — % of documents encrypted per container

- [ ] **6.3.2** Add AKV diagnostic logging
  - Enable AKV diagnostics → Log Analytics workspace
  - Alert on: unexpected IP access, high error rate, key deletion attempts

- [ ] **6.3.3** Add encryption audit endpoint to platform-service
  - `GET /api/admin/encryption-status` — returns per-product encryption coverage

  ```json
  {
    "products": [
      {
        "productId": "lysnrai",
        "containers": [
          {
            "name": "transcripts",
            "field": "transcriptText",
            "total": 10000,
            "encrypted": 9500,
            "coverage": "95%"
          }
        ]
      }
    ]
  }
  ```

- [ ] **6.3.4** Add encryption status to admin dashboard Ops page
  - Table showing encryption coverage per product/container
  - Migration trigger button (admin-only)

**Commit:** `feat(monitoring): encryption telemetry, AKV diagnostics, audit endpoint`

#### 6.4 Key Rotation Runbooks

- [ ] **6.4.1** Write MEK rotation runbook

  ```
  1. Create new MEK version in AKV (az keyvault key rotate)
  2. Run DEK re-wrap script: scripts/rotate-mek.ts --product lysnrai
  3. Verify decryption still works (run tests)
  4. Update AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md
  ```

- [ ] **6.4.2** Write DEK rotation runbook (per-user key refresh)
- [ ] **6.4.3** Write emergency key revocation runbook
- [ ] **6.4.4** Add rotation schedule to `AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md`

**Commit:** `docs(devops): encryption key rotation runbooks`

#### 6.5 Documentation Updates

- [ ] **6.5.1** Update all product `AGENTS.md` files with encryption conventions

  ```markdown
  ### Encryption

  - Sensitive fields encrypted via `@bytelyst/field-encrypt`
  - Encryption singleton in `backend/src/lib/field-encrypt.ts`
  - Tests use `memory` key provider (no env vars needed)
  - Production uses `akv` key provider with product-specific MEK
  ```

- [ ] **6.5.2** Update `AZURE_KEY_VAULT_AND_SECRETS_ROTATION.md` with MEK section
- [ ] **6.5.3** Update `ENVIRONMENT_VARIABLES_AND_KEYVAULT_AUDIT.md` with new env vars
- [ ] **6.5.4** Update `AZURE_RESOURCE_INVENTORY.md` with new AKV keys + containers
- [ ] **6.5.5** Write `docs/BEST_PRACTICES/ENCRYPTION.md` — developer guide for adding encryption to new fields

**Commit:** `docs: comprehensive encryption documentation across all repos`

**Sprint 6 deliverable:** Complete encryption story — blob CMK, migration tooling, monitoring, key rotation runbooks, full documentation.

---

## Test Plan

### Package Tests

| Package                        | Tests (estimated) | Coverage                                                    |
| ------------------------------ | :---------------: | ----------------------------------------------------------- |
| `@bytelyst/field-encrypt`      |        30         | AES-GCM, envelope, providers, cache, migration, type guard  |
| `@bytelyst/client-encrypt`     |        15         | Web Crypto encrypt/decrypt, PBKDF2, roundtrip               |
| `@bytelyst/e2ee-core`          |        20         | Keypair gen, recovery phrase, encrypt/decrypt, key exchange |
| `@bytelyst/secure-storage-web` |        10         | IndexedDB CRUD, fallback, CryptoKey persistence             |

### Integration Tests (per product)

Each product backend gets 3-5 new tests:

- Encrypt → store → read → decrypt roundtrip
- Migration: plaintext → encrypted (idempotent)
- Encrypted field detection (`isEncrypted()`)
- Batch encrypt/decrypt
- Config: memory provider works without env vars

**Total estimated new tests: ~120**

### E2E Verification

- [ ] Manual: Create encrypted note in NoteLett, verify ciphertext in Cosmos Data Explorer
- [ ] Manual: Create private agent in JarvisJr, verify server cannot read transcript
- [ ] Manual: Rotate MEK, verify all reads still work
- [ ] Manual: Run migration script on test container, verify 100% coverage

---

## Risk Register

| #   | Risk                                                  | Likelihood | Impact   | Mitigation                                                                                     |
| --- | ----------------------------------------------------- | ---------- | -------- | ---------------------------------------------------------------------------------------------- |
| R1  | AKV RBAC migration breaks existing services           | Medium     | High     | Test in staging first. Keep access policy backup. Immediate rollback plan.                     |
| R2  | DEK cache memory pressure on high-user-count services | Low        | Medium   | Configurable max cache size. LRU eviction. Monitor memory usage.                               |
| R3  | Encryption migration corrupts data                    | Low        | Critical | Dry-run mode first. Backup before migration. Idempotent (skip already-encrypted).              |
| R4  | AKV outage blocks all reads/writes                    | Low        | Critical | DEK cache (15 min) provides buffer. Env key provider as emergency fallback.                    |
| R5  | Performance regression on high-throughput endpoints   | Low        | Medium   | AES-256-GCM is hardware-accelerated. DEK cache avoids AKV round-trips. Benchmark before/after. |
| R6  | E2EE key loss = permanent data loss                   | Medium     | Critical | Recovery phrase (12 words). Prominent UI warnings. Confirmation flow before enabling.          |
| R7  | Cosmos RU increase from larger encrypted documents    | Low        | Low      | ~15-20% doc size increase. Monitor RU consumption.                                             |
| R8  | FTS5/search breaks on encrypted fields                | Medium     | Medium   | Maintain plaintext search index or use extraction-service for keywords.                        |

---

## Success Metrics

| Metric                   | Target                                                   | Measured By                 |
| ------------------------ | -------------------------------------------------------- | --------------------------- |
| **Encryption coverage**  | 100% of P0 fields encrypted within 8 weeks               | Audit endpoint              |
| **Zero plaintext leaks** | 0 unencrypted sensitive fields in Cosmos after migration | Audit scan                  |
| **Performance impact**   | < 5% latency increase on encrypted endpoints             | Backend metrics             |
| **Test coverage**        | 120+ new encryption tests                                | Vitest/XCTest/JUnit reports |
| **DEK cache hit rate**   | > 95%                                                    | Telemetry                   |
| **Key rotation time**    | < 30 min for full MEK rotation                           | Runbook timing              |
| **Developer experience** | < 10 LOC to encrypt a new field                          | Code review                 |

---

## Cost Estimate

| Item                       |  Monthly Cost   | Notes                                      |
| -------------------------- | :-------------: | ------------------------------------------ |
| AKV RSA keys (10 MEKs)     |     $10-50      | $1/key (software) or $5/key (HSM)          |
| AKV operations (DEK wraps) |       $0        | Within free tier (10K/month)               |
| Cosmos RU increase         |      ~$2-5      | 15-20% larger docs on encrypted containers |
| Compute (AES-GCM)          |       ~$0       | Hardware-accelerated, negligible           |
| **Total**                  | **< $60/month** |                                            |

---

## Decision Log

| Date       | Decision                                 | Rationale                                                                                                               |
| ---------- | ---------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
| 2026-03-21 | Use AES-256-GCM for all field encryption | AEAD, native on all platforms, NIST approved, matches existing MFA pattern                                              |
| 2026-03-21 | Envelope encryption (MEK → DEK)          | Enables key rotation without re-encrypting all data; per-user isolation                                                 |
| 2026-03-21 | Tier 3 E2EE only for JarvisJr + NoteLett | Server-side AI in other products requires plaintext access                                                              |
| 2026-03-21 | Skip ChronoMind + PeakPulse encryption   | Timer configs and GPS stats are not sensitive data                                                                      |
| 2026-03-21 | RSA-4096 for MEKs                        | Maximum classical security margin; AKV native support. Not quantum-resistant — plan PQC migration when AKV supports it. |
| 2026-03-21 | 15-min DEK cache TTL                     | Balances AKV rate limits vs key exposure window                                                                         |
| 2026-03-21 | `__encrypted` sentinel in documents      | Enables gradual migration without schema changes                                                                        |

---

## Appendix: Sprint Checkpoint Verification

After each sprint, run:

```bash
# ── Package tests ──────────────────────────────────
cd learning_ai_common_plat && pnpm build && pnpm test

# ── All product backends ───────────────────────────
cd learning_voice_ai_agent/backend && npm test        # LysnrAI
cd learning_ai_jarvis_jr/backend && npm test           # JarvisJr
cd learning_ai_notes/backend && npm test               # NoteLett
cd learning_multimodal_memory_agents/backend && npm test # MindLyst
cd learning_ai_fastgap/backend && npm test             # NomGap
cd learning_ai_trails/backend && npm test              # ActionTrail
cd learning_ai_flowmonk/backend && npm test            # FlowMonk
cd learning_ai_local_memory_gpt/backend && npm test    # LocalMemGPT

# ── Platform service ──────────────────────────────
cd learning_ai_common_plat && pnpm --filter @lysnrai/platform-service test

# ── Type check everything ──────────────────────────
cd learning_ai_common_plat && pnpm typecheck
```
