# Phase 3: Filesystem Storage Migration ## Agent Assignment **Primary Agent:** storage-agent **Duration:** 30-40 minutes ## Prerequisites - None (can start immediately) ## Objectives 1. Create filesystem storage adapter 2. Replace MinIO adapter with filesystem 3. Update documents feature to use filesystem 4. Verify document upload/download works ## Step-by-Step Instructions ### Step 1: Create Filesystem Adapter Create `backend/src/core/storage/adapters/filesystem.adapter.ts`: ```typescript import { StorageService } from '../storage.service'; import * as fs from 'fs/promises'; import * as path from 'path'; import { createReadStream } from 'fs'; export class FilesystemAdapter implements StorageService { private basePath: string; constructor(basePath: string = '/app/data/documents') { this.basePath = basePath; } async putObject(bucket: string, key: string, body: Buffer, contentType?: string): Promise { const filePath = path.join(this.basePath, key); await fs.mkdir(path.dirname(filePath), { recursive: true }); await fs.writeFile(filePath, body); } async getObjectStream(bucket: string, key: string): Promise { const filePath = path.join(this.basePath, key); return createReadStream(filePath); } async deleteObject(bucket: string, key: string): Promise { const filePath = path.join(this.basePath, key); await fs.unlink(filePath); } async headObject(bucket: string, key: string): Promise { const filePath = path.join(this.basePath, key); const stats = await fs.stat(filePath); return { size: stats.size, lastModified: stats.mtime }; } async getSignedUrl(bucket: string, key: string): Promise { // Not needed for filesystem, return direct path return `/api/documents/download/${key}`; } } ``` ### Step 2: Update Storage Service Factory Modify `backend/src/core/storage/storage.service.ts`: ```typescript import { FilesystemAdapter } from './adapters/filesystem.adapter'; export function getStorageService(): StorageService { // Always use filesystem adapter return new FilesystemAdapter('/app/data/documents'); } ``` ### Step 3: Verify Documents Feature No changes needed to documents.controller.ts - it uses StorageService interface. Storage keys will be filesystem paths: `documents/{userId}/{vehicleId}/{documentId}/{filename}` ### Step 4: Test Document Upload ```bash # Rebuild backend cd backend && npm run build # Restart backend docker compose restart mvp-backend # Test upload (requires authentication) curl -X POST https://admin.motovaultpro.com/api/documents \ -H "Authorization: Bearer $TOKEN" \ -F "file=@test.pdf" \ -F "vehicleId=123" # Verify file exists docker compose exec mvp-backend ls -la /app/data/documents/ ``` ## Validation Criteria - [ ] FilesystemAdapter created - [ ] getStorageService returns FilesystemAdapter - [ ] Document upload works - [ ] Document download works - [ ] Files stored in /app/data/documents/ - [ ] No MinIO references in code **Validation Command:** ```bash grep -r "minio\|MinIO" backend/src/ | wc -l # Expected: 0 ``` ## Update EXECUTION-STATE.json ```json { "phases": {"3": {"status": "completed", "validation_passed": true}} } ```