debug(auth): log session cookie source
This commit is contained in:
238
plans/prisma-middleware-migration-plan.md
Normal file
238
plans/prisma-middleware-migration-plan.md
Normal file
@@ -0,0 +1,238 @@
|
||||
# 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`
|
||||
Reference in New Issue
Block a user