debug(auth): log session cookie source
All checks were successful
ci/woodpecker/push/infra Pipeline was successful
ci/woodpecker/push/orchestrator Pipeline was successful
ci/woodpecker/push/api Pipeline was successful
ci/woodpecker/push/web Pipeline was successful

This commit is contained in:
2026-02-18 21:30:00 -06:00
parent fa9f173f8e
commit af299abdaf
21 changed files with 1502 additions and 78 deletions

View File

@@ -0,0 +1,657 @@
# Mosaic Stack Comprehensive Installer Plan
## Executive Summary
This document outlines the plan for creating a comprehensive installation script for Mosaic Stack that "just works" across platforms, automatically installs all dependencies, detects the platform, and configures the system. The design is inspired by the OpenClaw installer pattern while addressing Mosaic Stack's unique requirements as a multi-tenant personal assistant platform with optional Docker deployment.
---
## 1. Current State Analysis
### 1.1 Existing Setup Script ([`scripts/setup.sh`](scripts/setup.sh))
**Strengths:**
- Interactive configuration wizard
- Platform detection (Debian, Arch, Fedora, macOS)
- Docker and native deployment modes
- Port conflict detection and resolution
- .env file management with value preservation
- Secret generation
- SSO/Authentik configuration
- Ollama integration options
- Traefik reverse proxy support
**Gaps:**
- No curl-able one-liner installation
- Missing automatic dependency installation for some platforms
- No WSL detection/handling
- No dry-run validation of full configuration
- Limited post-install validation
- No upgrade/migration path handling
- Missing verbose/debug mode
- No cleanup on failure
- PATH management not comprehensive
### 1.2 OpenClaw Installer Features to Adopt
| Feature | Description | Priority |
| ------------------------ | -------------------------------------------------------- | -------- |
| curl-able one-liner | `curl -fsSL URL \| bash` pattern | High |
| Color output | Consistent colored output with ACCENT/SUCCESS/WARN/ERROR | High |
| Platform detection | macOS, Linux, WSL detection | High |
| Auto Homebrew | Automatic Homebrew installation on macOS | Medium |
| Node.js management | NodeSource integration for Linux, Homebrew for macOS | High |
| npm permissions fix | User-local npm global installs on Linux | Medium |
| pnpm via corepack | Corepack-first pnpm installation | High |
| Git installation | Automatic Git installation | Medium |
| Multiple install methods | npm vs git checkout options | Low |
| Dry-run mode | Preview changes without execution | High |
| Verbose mode | Debug output with `set -x` | Medium |
| Non-interactive mode | CI/CD friendly automation | High |
| TTY detection | Graceful handling of piped input | High |
| Temp file cleanup | Trap-based cleanup on exit | High |
| Downloader detection | curl/wget abstraction | Medium |
| PATH warnings | Alert user about PATH issues | Medium |
| Post-install doctor | Validation and migration | High |
| Fun taglines | User-friendly messaging | Low |
---
## 2. Proposed Architecture
### 2.1 File Structure
```
scripts/
├── install.sh # Main entry point (curl-able)
├── setup.sh # Interactive configuration wizard (enhanced)
├── lib/
│ ├── common.sh # Shared utilities (enhanced)
│ ├── platform.sh # Platform detection functions
│ ├── dependencies.sh # Dependency installation functions
│ ├── docker.sh # Docker-specific functions
│ ├── native.sh # Native deployment functions
│ └── validation.sh # Post-install validation
└── commands/
├── doctor.sh # Diagnostic and repair tool
└── upgrade.sh # Upgrade/migration handler
```
### 2.2 Installer Flow Diagram
```mermaid
flowchart TD
A[curl/install.sh] --> B{Parse Arguments}
B --> C{Help?}
C -->|Yes| D[Show Usage]
C -->|No| E{Dry Run?}
E --> F[Detect Platform]
F --> G[Detect Package Manager]
G --> H{Install Method}
H -->|docker| I[Check Docker]
H -->|native| J[Check Node.js/pnpm]
I --> K{Docker OK?}
K -->|No| L[Install Docker]
K -->|Yes| M[Check Docker Compose]
L --> M
J --> N{Node.js OK?}
N -->|No| O[Install Node.js]
N -->|Yes| P{pnpm OK?}
O --> P
P -->|No| Q[Install pnpm]
P -->|Yes| R[Check PostgreSQL]
Q --> R
M --> S[Check Existing Config]
R --> S
S --> T{Has .env?}
T -->|Yes| U[Load Existing Values]
T -->|No| V[Interactive Config]
U --> V
V --> W[Generate Secrets]
W --> X[Resolve Port Conflicts]
X --> Y[Write .env]
Y --> Z{Deployment Mode}
Z -->|docker| AA[Docker Compose Up]
Z -->|native| AB[Run Migrations]
AA --> AC[Run Doctor]
AB --> AC
AC --> AD{All Checks Pass?}
AD -->|Yes| AE[Show Success]
AD -->|No| AF[Show Warnings]
AE --> AG[Print Next Steps]
AF --> AG
```
---
## 3. Detailed Component Design
### 3.1 Entry Point: `install.sh`
The main installer should support both quick-start and advanced usage:
```bash
# Usage patterns:
# Quick start (interactive):
curl -fsSL https://get.mosaicstack.dev | bash
# Non-interactive Docker deployment:
curl -fsSL https://get.mosaicstack.dev | bash -s -- --non-interactive --mode docker
# Dry run to preview:
curl -fsSL https://get.mosaicstack.dev | bash -s -- --dry-run --mode docker
# With all options:
curl -fsSL https://get.mosaicstack.dev | bash -s -- \
--mode docker \
--enable-sso \
--bundled-authentik \
--ollama-mode local \
--base-url https://mosaic.example.com
```
**Command-line Options:**
| Option | Description | Default |
| -------------------------- | ------------------------------- | --------------------- |
| `--mode` | Deployment mode: docker, native | interactive |
| `--non-interactive` | Skip all prompts | false |
| `--dry-run` | Preview without changes | false |
| `--verbose` | Enable debug output | false |
| `--enable-sso` | Enable Authentik SSO | false |
| `--bundled-authentik` | Use bundled Authentik | false |
| `--external-authentik URL` | External Authentik URL | - |
| `--ollama-mode` | Ollama: local, remote, disabled | disabled |
| `--ollama-url URL` | Remote Ollama URL | - |
| `--base-url URL` | Mosaic base URL | http://localhost:3000 |
| `--profiles` | Compose profiles to enable | full |
| `--no-port-check` | Skip port conflict detection | false |
| `--skip-deps` | Skip dependency installation | false |
| `--help` | Show usage | - |
### 3.2 Platform Detection: `lib/platform.sh`
```bash
# Functions to implement:
detect_os() # Returns: macos, debian, arch, fedora, linux, unknown
detect_package_manager() # Returns: brew, apt, pacman, dnf, unknown
detect_wsl() # Returns: WSL_DISTRO_NAME or empty
detect_init_system() # Returns: systemd, openrc, launchd, unknown
get_os_name() # Human-readable OS name
get_arch() # Returns: x86_64, aarch64, armv7l
is_root() # Check if running as root
maybe_sudo() # Run with sudo only if needed
```
**Platform Support Matrix:**
| Platform | Package Manager | Init System | Node.js Source |
| ------------- | ---------------- | ----------- | ---------------- |
| macOS | Homebrew | launchd | Homebrew |
| Ubuntu/Debian | apt | systemd | NodeSource |
| Arch/Manjaro | pacman | systemd | pacman |
| Fedora/RHEL | dnf | systemd | NodeSource |
| WSL | (host-dependent) | systemd\* | (host-dependent) |
### 3.3 Dependency Management: `lib/dependencies.sh`
**Dependencies by Mode:**
**Docker Mode:**
- Docker Engine 24+
- Docker Compose (plugin or standalone)
- Git (for cloning if needed)
**Native Mode:**
- Node.js 22+
- pnpm 10+
- PostgreSQL 17+ (with pgvector)
- Valkey/Redis (optional)
- Git
**Optional Dependencies:**
- Ollama (for local LLM)
- OpenSSL (for secret generation)
**Installation Strategy:**
```bash
# macOS
install_homebrew() # Auto-install Homebrew if missing
install_docker_macos() # via Homebrew
install_node_macos() # via Homebrew
install_pnpm() # via corepack or npm
# Debian/Ubuntu
install_docker_debian() # via docker.com apt repo
install_node_debian() # via NodeSource
install_postgres_debian() # via apt with pgvector
# Arch Linux
install_docker_arch() # via pacman
install_node_arch() # via pacman
install_postgres_arch() # via pacman with pgvector
# Fedora/RHEL
install_docker_fedora() # via dnf
install_node_fedora() # via NodeSource
install_postgres_fedora() # via dnf
```
### 3.4 Docker Functions: `lib/docker.sh`
```bash
check_docker() # Verify Docker is installed and accessible
check_docker_compose() # Verify Docker Compose is available
check_docker_buildx() # Verify buildx is available
fix_docker_permissions() # Add user to docker group
start_docker() # Start Docker daemon if not running
docker_pull_images() # Pre-pull all required images
docker_compose_up() # Start services with health checks
docker_compose_down() # Stop services
docker_logs() # Tail logs for debugging
```
### 3.5 Configuration Generation
**Environment File Structure:**
The installer should generate a complete `.env` file based on:
1. **Existing values** (if `.env` exists)
2. **Command-line arguments**
3. **Interactive prompts** (if TTY available)
4. **Auto-detected defaults**
**Secret Generation:**
| Secret | Length | Method |
| ---------------------------- | ------ | -------------------- |
| POSTGRES_PASSWORD | 32 | openssl rand -base64 |
| JWT_SECRET | 32 | openssl rand -base64 |
| BETTER_AUTH_SECRET | 32 | openssl rand -base64 |
| ENCRYPTION_KEY | 32 | openssl rand -hex 32 |
| AUTHENTIK_SECRET_KEY | 50 | openssl rand -base64 |
| AUTHENTIK_BOOTSTRAP_PASSWORD | 16 | openssl rand -base64 |
| COORDINATOR_API_KEY | 32 | openssl rand -base64 |
| ORCHESTRATOR_API_KEY | 32 | openssl rand -base64 |
| GITEA_WEBHOOK_SECRET | 32 | openssl rand -hex 32 |
**URL Derivation:**
```bash
# Localhost mode
MOSAIC_BASE_URL=http://localhost:${WEB_PORT}
NEXT_PUBLIC_API_URL=http://localhost:${API_PORT}
# Domain mode (with Traefik)
MOSAIC_BASE_URL=https://${MOSAIC_WEB_DOMAIN}
NEXT_PUBLIC_API_URL=https://${MOSAIC_API_DOMAIN}
# IP mode (local network)
MOSAIC_BASE_URL=http://${LOCAL_IP}:${WEB_PORT}
NEXT_PUBLIC_API_URL=http://${LOCAL_IP}:${API_PORT}
```
### 3.6 Port Conflict Resolution
```bash
# Default ports
declare -A DEFAULT_PORTS=(
[WEB_PORT]=3000
[API_PORT]=3001
[POSTGRES_PORT]=5432
[VALKEY_PORT]=6379
[AUTHENTIK_PORT_HTTP]=9000
[AUTHENTIK_PORT_HTTPS]=9443
[OLLAMA_PORT]=11434
[TRAEFIK_HTTP_PORT]=80
[TRAEFIK_HTTPS_PORT]=443
[TRAEFIK_DASHBOARD_PORT]=8080
)
# Check if port is in use
check_port_in_use() {
local port=$1
# Try ss first, fall back to netstat, then lsof
}
# Suggest alternative port
suggest_alternative_port() {
local base_port=$1
# Try base_port+1, base_port+100, etc.
}
```
### 3.7 Post-Install Validation: `lib/validation.sh`
**Doctor Checks:**
```bash
# Docker mode checks
doctor_docker_running() # Docker daemon is running
doctor_containers_healthy() # All containers are healthy
doctor_database_connected() # PostgreSQL is accessible
doctor_cache_connected() # Valkey is accessible
doctor_api_responding() # API health check passes
doctor_web_responding() # Web frontend is accessible
# Native mode checks
doctor_node_version() # Node.js version is sufficient
doctor_pnpm_version() # pnpm is installed
doctor_postgres_running() # PostgreSQL is running
doctor_migrations_applied() # Database migrations are up to date
doctor_dependencies_installed() # node_modules is complete
# General checks
doctor_env_complete() # All required env vars are set
doctor_secrets_valid() # Secrets are not placeholders
doctor_ports_available() # Configured ports are available
doctor_disk_space() # Sufficient disk space
```
### 3.8 Doctor Command: `scripts/commands/doctor.sh`
A standalone diagnostic tool that can be run after installation:
```bash
# Usage
./scripts/commands/doctor.sh # Run all checks
./scripts/commands/doctor.sh --fix # Attempt automatic fixes
./scripts/commands/doctor.sh --verbose # Detailed output
./scripts/commands/doctor.sh --json # JSON output for CI
# Exit codes
# 0: All checks passed
# 1: Some checks failed
# 2: Critical failure
```
---
## 4. User Experience Design
### 4.1 Banner and Branding
```
__ __ _ ____ _ _
| \/ | ___ ___ __ _(_) ___ / ___| |_ __ _ ___| | __
| |\/| |/ _ \/ __|/ _` | |/ __|\___ | __/ _` |/ __| |/ /
| | | | (_) \__ \ (_| | | (__ ___/ | || (_| | (__| <
|_| |_|\___/|___/\__,_|_|\___|____/ \__\__,_|\___|_|\_\
Multi-Tenant Personal Assistant Platform
Claws out, configs in — let's ship a calm, clean stack.
```
### 4.2 Progress Indicators
```
✓ Detected: macOS (brew)
✓ Docker: OK (version 27.0.0)
✓ Docker Compose: OK (version 2.28.0)
✓ Node.js: OK (v22.5.0)
⚠ Port 3000 is in use, using 3001
→ Generating secrets...
→ Writing .env file...
→ Starting services...
✓ All services healthy
```
### 4.3 Error Messages
```
✗ Docker is not running
Start with: open -a Docker (macOS)
Start with: sudo systemctl start docker (Linux)
✗ Port conflicts detected:
- Web UI (3000): In use by process 12345 (node)
- API (3001): In use by process 12346 (python)
Run with --auto-ports to use alternative ports
```
### 4.4 Success Message
```
════════════════════════════════════════════════════════════
Mosaic Stack is ready!
════════════════════════════════════════════════════════════
Web UI: http://localhost:3000
API: http://localhost:3001
Database: localhost:5432
Next steps:
1. Open http://localhost:3000 in your browser
2. Create your first workspace
3. Configure AI providers in Settings
To stop: docker compose down
To restart: docker compose restart
To view logs: docker compose logs -f
Documentation: https://docs.mosaicstack.dev
Support: https://github.com/mosaicstack/stack/issues
```
---
## 5. Implementation Phases
### Phase 1: Core Infrastructure
- [ ] Create `install.sh` entry point with argument parsing
- [ ] Implement platform detection in `lib/platform.sh`
- [ ] Create dependency checking functions
- [ ] Add temp file cleanup and error handling
- [ ] Implement colored output system
### Phase 2: Dependency Installation
- [ ] Implement Homebrew auto-installation for macOS
- [ ] Implement Docker installation for all platforms
- [ ] Implement Node.js installation via NodeSource (Debian/Fedora)
- [ ] Implement pnpm installation via corepack
- [ ] Implement PostgreSQL installation with pgvector
### Phase 3: Configuration
- [ ] Enhance .env file generation
- [ ] Implement secret generation with proper entropy
- [ ] Add URL derivation logic for all access modes
- [ ] Implement port conflict detection and resolution
- [ ] Add configuration validation
### Phase 4: Service Management
- [ ] Implement Docker Compose service orchestration
- [ ] Add health check polling
- [ ] Implement database migration running
- [ ] Add service status reporting
### Phase 5: Validation and Doctor
- [ ] Create `scripts/commands/doctor.sh`
- [ ] Implement all diagnostic checks
- [ ] Add automatic fix capabilities
- [ ] Create JSON output mode for CI
### Phase 6: Polish and Testing
- [ ] Add comprehensive logging
- [ ] Test on all supported platforms
- [ ] Test upgrade scenarios
- [ ] Write documentation
- [ ] Create CI/CD integration examples
---
## 6. Testing Strategy
### 6.1 Platform Testing Matrix
| Platform | Version | Docker | Native | CI |
| -------- | ------------- | ------ | ------ | -------------- |
| macOS | 14 (Sonoma) | ✓ | ✓ | Manual |
| macOS | 13 (Ventura) | ✓ | ✓ | Manual |
| Ubuntu | 24.04 LTS | ✓ | ✓ | GitHub Actions |
| Ubuntu | 22.04 LTS | ✓ | ✓ | GitHub Actions |
| Debian | 12 (Bookworm) | ✓ | ✓ | GitHub Actions |
| Arch | Rolling | ✓ | ✓ | Manual |
| Fedora | 40 | ✓ | ✓ | Manual |
| WSL2 | Ubuntu | ✓ | ✓ | Manual |
### 6.2 Test Scenarios
1. **Fresh Installation**
- No dependencies installed
- Clean system
2. **Partial Dependencies**
- Some dependencies already installed
- Different versions
3. **Upgrade Scenario**
- Existing .env file
- Running containers
4. **Port Conflicts**
- Common ports in use
- All ports in use
5. **Error Recovery**
- Network failures
- Permission issues
- Disk space issues
---
## 7. Security Considerations
### 7.1 Secret Handling
- Never log secrets to console or file
- Generate secrets with cryptographically secure random
- Validate secrets are not placeholders before starting
- Warn if default/weak secrets are detected
### 7.2 Network Security
- Download scripts over HTTPS only
- Verify TLS certificates
- Use specific version tags for Docker images
- Pin NodeSource repository version
### 7.3 File Permissions
- Set restrictive permissions on .env (600)
- Ensure secrets are not world-readable
- Validate file ownership
---
## 8. Documentation Requirements
### 8.1 README Updates
- Add installation section with curl command
- Document all command-line options
- Add troubleshooting section
- Include platform-specific notes
### 8.2 Inline Documentation
- Comment all functions with usage examples
- Document expected return values
- Include error codes
### 8.3 User Guide
- Step-by-step installation guide
- Configuration options explained
- Common issues and solutions
- Upgrade procedures
---
## 9. Open Questions
1. **Should we support Windows native installation?**
- Current recommendation: WSL2 only
- PowerShell version could be a future addition
2. **Should we support ARM platforms (Raspberry Pi)?**
- Docker images would need ARM builds
- Could be community-supported
3. **What is the upgrade strategy?**
- In-place upgrade vs. migrate data
- Database migration handling
- Configuration file changes
4. **Should we provide an uninstaller?**
- Clean up Docker volumes
- Remove configuration files
- Uninstall dependencies (optional)
---
## 10. Success Criteria
The installer is considered successful when:
1. ✅ A user can run `curl -fsSL https://get.mosaicstack.dev | bash` and have a working installation
2. ✅ All dependencies are automatically installed on supported platforms
3. ✅ Port conflicts are automatically detected and resolved
4. ✅ Secrets are automatically generated with proper entropy
5. ✅ The installation completes in under 5 minutes on a fresh system
6. ✅ Post-install validation confirms all services are healthy
7. ✅ Clear next steps are provided to the user
8. ✅ Non-interactive mode works for CI/CD pipelines
9. ✅ The doctor command can diagnose and fix common issues
10. ✅ Upgrade from previous versions preserves data and configuration
---
## Appendix A: Environment Variables Reference
See [`.env.example`](.env.example) for the complete list of configuration options.
## Appendix B: Docker Compose Profiles
| Profile | Services | Use Case |
| ----------------- | ------------ | ------------------- |
| `full` | All services | Development/Trial |
| `database` | PostgreSQL | External cache/auth |
| `cache` | Valkey | External database |
| `authentik` | Authentik | SSO enabled |
| `ollama` | Ollama | Local LLM |
| `traefik-bundled` | Traefik | Reverse proxy |
| `openbao` | OpenBao | Secrets management |
## Appendix C: Related Files
- Current setup script: [`scripts/setup.sh`](scripts/setup.sh)
- Common utilities: [`scripts/lib/common.sh`](scripts/lib/common.sh)
- Docker Compose: [`docker-compose.yml`](docker-compose.yml)
- Environment example: [`.env.example`](.env.example)
- OpenClaw installer reference: [`examples/openclaw/install.sh`](examples/openclaw/install.sh)

View 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`