Files
motovaultpro/docs/redesign/PHASE-03-FILESYSTEM-STORAGE.md
Eric Gullickson 046c66fc7d Redesign
2025-11-01 21:27:42 -05:00

3.2 KiB

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:

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<void> {
    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<NodeJS.ReadableStream> {
    const filePath = path.join(this.basePath, key);
    return createReadStream(filePath);
  }

  async deleteObject(bucket: string, key: string): Promise<void> {
    const filePath = path.join(this.basePath, key);
    await fs.unlink(filePath);
  }

  async headObject(bucket: string, key: string): Promise<any> {
    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<string> {
    // 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:

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

# 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:

grep -r "minio\|MinIO" backend/src/ | wc -l
# Expected: 0

Update EXECUTION-STATE.json

{
  "phases": {"3": {"status": "completed", "validation_passed": true}}
}