# Prisma Middleware Migration Plan: $use to $extends

## Problem Summary

The application fails to start with the following error:

```
TypeError: prisma.$use is not a function
    at registerAccountEncryptionMiddleware (/app/apps/api/dist/prisma/account-encryption.middleware.js:45:12)
```

### Root Cause

The project uses **Prisma 6.19.2**, which removed the deprecated `$use()` middleware API. The `$use()` method was deprecated in Prisma4.16.0 and removed in Prisma5.0.0. The replacement is **Prisma Client Extensions** using the `$extends()` API.

### Affected Files

| File                                                                                                 | Purpose                                                  |
| ---------------------------------------------------------------------------------------------------- | -------------------------------------------------------- |
| [`account-encryption.middleware.ts`](apps/api/src/prisma/account-encryption.middleware.ts)           | Encrypts/decrypts OAuth tokens in Account table          |
| [`llm-encryption.middleware.ts`](apps/api/src/prisma/llm-encryption.middleware.ts)                   | Encrypts/decrypts API keys in LlmProviderInstance.config |
| [`prisma.service.ts`](apps/api/src/prisma/prisma.service.ts)                                         | Registers both middleware functions                      |
| [`account-encryption.middleware.spec.ts`](apps/api/src/prisma/account-encryption.middleware.spec.ts) | Unit tests for account encryption                        |
| [`llm-encryption.middleware.spec.ts`](apps/api/src/prisma/llm-encryption.middleware.spec.ts)         | Unit tests for LLM encryption                            |
| [`prisma.service.spec.ts`](apps/api/src/prisma/prisma.service.spec.ts)                               | Unit tests for PrismaService                             |

---

## Migration Strategy

### Current Architecture (Broken)

```mermaid
flowchart TD
    A[PrismaService.onModuleInit] --> B[$connect to database]
    B --> C[registerAccountEncryptionMiddleware]
    B --> D[registerLlmEncryptionMiddleware]
    C --> E[prisma.$use - REMOVED IN PRISMA5]
    D --> F[prisma.$use - REMOVED IN PRISMA5]
    E --> G[ERROR: $use is not a function]
    F --> G
```

### Target Architecture (Client Extensions)

```mermaid
flowchart TD
    A[PrismaService] --> B[Create Extended Client]
    B --> C[prisma.$extends with Account query override]
    B --> D[prisma.$extends with LlmProviderInstance query override]
    C --> E[Extended Client with transparent encryption]
    D --> E
    E --> F[All queries use extended client automatically]
```

---

## Implementation Tasks

### Phase 1: Create Extension Functions

#### Task 1.1: Create Account Encryption Extension

Replace [`account-encryption.middleware.ts`](apps/api/src/prisma/account-encryption.middleware.ts) with a Client Extension:

**Key changes:**

- Remove `registerAccountEncryptionMiddleware` function
- Create `createAccountEncryptionExtension` function that returns a Prisma extension
- Use `prisma.$extends({ query: { account: { ... } } })` pattern
- Override `$allOperations` or specific operations: `create`, `update`, `upsert`, `findUnique`, `findFirst`, `findMany`

**Extension structure:**

```typescript
export function createAccountEncryptionExtension(prisma: PrismaClient, vaultService: VaultService) {
  return prisma.$extends({
    query: {
      account: {
        async $allOperations({ model, operation, args, query }) {
          // Pre-operation: encrypt on writes
          // Execute: call original query
          // Post-operation: decrypt on reads
        },
      },
    },
  });
}
```

#### Task 1.2: Create LLM Encryption Extension

Replace [`llm-encryption.middleware.ts`](apps/api/src/prisma/llm-encryption.middleware.ts) with similar Client Extension pattern for `LlmProviderInstance` model.

### Phase 2: Update PrismaService

#### Task 2.1: Modify PrismaService to Use Extensions

Update [`prisma.service.ts`](apps/api/src/prisma/prisma.service.ts:28-45):

**Current code:**

```typescript
async onModuleInit() {
  await this.$connect();
  registerAccountEncryptionMiddleware(this, this.vaultService);
  registerLlmEncryptionMiddleware(this, this.vaultService);
}
```

**New approach:**

- Create extended client in constructor or onModuleInit
- Store extended client as property
- Export extended client for use throughout application

**Challenge:** PrismaService extends PrismaClient. We need to decide:

- Option A: Return extended client from a getter method
- Option B: Create a wrapper that delegates to extended client
- Option C: Use composition instead of inheritance

**Recommended: Option A with factory pattern**

```typescript
@Injectable()
export class PrismaService {
  private readonly baseClient: PrismaClient;
  private readonly extendedClient: ExtendedPrismaClient;

  constructor(vaultService: VaultService) {
    this.baseClient = new PrismaClient({...});
    this.extendedClient = createExtendedClient(this.baseClient, vaultService);
  }

  // Delegate all PrismaClient methods to extended client
  get $queryRaw() { return this.extendedClient.$queryRaw; }
  // ... other delegates
}
```

### Phase 3: Update Unit Tests

#### Task 3.1: Update account-encryption.middleware.spec.ts

- Change mock from `$use` to `$extends`
- Update test structure to work with extension pattern
- Test that extension correctly intercepts queries

#### Task 3.2: Update llm-encryption.middleware.spec.ts

Same updates as Task 3.1 for LLM encryption.

#### Task 3.3: Update prisma.service.spec.ts

- Remove `$use` mock
- Update to test extension registration

### Phase 4: Integration Testing

#### Task 4.1: Verify Encryption/Decryption Works

- Run existing integration tests
- Verify OAuth tokens are encrypted at rest
- Verify LLM API keys are encrypted at rest
- Verify transparent decryption on read

#### Task 4.2: Test Backward Compatibility

- Verify existing encrypted data can be decrypted
- Verify plaintext data is encrypted on next write

---

## Detailed Implementation Checklist

### Files to Modify

- [ ] `apps/api/src/prisma/account-encryption.middleware.ts`
  - Rename to `account-encryption.extension.ts` or keep name
  - Replace `$use` with `$extends` pattern
- [ ] `apps/api/src/prisma/llm-encryption.middleware.ts`
  - Rename to `llm-encryption.extension.ts` or keep name
  - Replace `$use` with `$extends` pattern

- [ ] `apps/api/src/prisma/prisma.service.ts`
  - Refactor to use extended client
  - Maintain backward compatibility for existing code

- [ ] `apps/api/src/prisma/account-encryption.middleware.spec.ts`
  - Update mocks and test structure

- [ ] `apps/api/src/prisma/llm-encryption.middleware.spec.ts`
  - Update mocks and test structure

- [ ] `apps/api/src/prisma/prisma.service.spec.ts`
  - Update mocks and test structure

- [ ] `apps/api/src/prisma/index.ts` (if exists)
  - Update exports if file names change

---

## Risk Assessment

| Risk                      | Impact   | Mitigation                                |
| ------------------------- | -------- | ----------------------------------------- |
| Breaking existing queries | High     | Comprehensive test coverage before/after  |
| Type safety issues        | Medium   | Use Prisma generated types with extension |
| Performance regression    | Low      | Extension overhead is minimal             |
| Data corruption           | Critical | Test with real encryption/decryption      |

---

## References

- [Prisma Client Extensions Documentation](https://www.prisma.io/docs/concepts/components/prisma-client/client-extensions)
- [Migration Guide: Middleware to Extensions](https://www.prisma.io/docs/concepts/components/prisma-client/middleware)
- Original TODO comments in code pointing to this migration

---

## Execution Order

1. **Code Mode**: Implement extension functions (Phase 1)
2. **Code Mode**: Update PrismaService (Phase 2)
3. **Code Mode**: Update unit tests (Phase 3)
4. **Debug Mode**: Integration testing and verification (Phase 4)

---

## User Decisions

- **File naming**: Rename middleware files to `.extension.ts` for clarity
  - `account-encryption.middleware.ts` → `account-encryption.extension.ts`
  - `llm-encryption.middleware.ts` → `llm-encryption.extension.ts`
  - `account-encryption.middleware.spec.ts` → `account-encryption.extension.spec.ts`
  - `llm-encryption.middleware.spec.ts` → `llm-encryption.extension.spec.ts`
