--- id: ADR-0006 type: ADR title: "Storage Abstraction" status: Accepted decision_date: 2026-01-10 updated_at: 2026-01-10 simco_version: "4.0.1" stakeholders: - "Equipo MiChangarrito" tags: - storage - s3 - r2 - abstraction - multi-cloud --- # ADR-0006: Storage Abstraction ## Metadata | Campo | Valor | |-------|-------| | **ID** | ADR-0006 | | **Estado** | Accepted | | **Fecha** | 2026-01-10 | | **Autor** | Architecture Team | | **Supersede** | - | --- ## Contexto MiChangarrito necesita almacenar archivos (imagenes de productos, facturas, documentos) en la nube. Queremos: 1. Flexibilidad para cambiar de proveedor 2. Desarrollo local sin depender de cloud 3. Optimizacion de costos (R2 es mas barato que S3) --- ## Decision **Implementamos una capa de abstraccion con Factory Pattern que soporta S3, Cloudflare R2 y MinIO.** Todos los proveedores implementan la misma interfaz, permitiendo cambiar de proveedor sin modificar codigo de negocio. ```typescript interface StorageProvider { upload(key: string, file: Buffer, options?: UploadOptions): Promise; download(key: string): Promise; delete(key: string): Promise; getSignedUrl(key: string, expiresIn: number): Promise; list(prefix: string): Promise; } ``` --- ## Alternativas Consideradas ### Opcion 1: Usar S3 directamente - **Pros:** - Simple - Bien documentado - **Cons:** - Vendor lock-in - Sin desarrollo local facil - Costos pueden ser altos ### Opcion 2: Abstraccion con Factory (Elegida) - **Pros:** - Flexibilidad de proveedor - MinIO para desarrollo local - Optimizacion de costos con R2 - Codigo limpio - **Cons:** - Complejidad adicional - Mantener multiples providers ### Opcion 3: Usar libreria existente (flydrive) - **Pros:** - Ya implementado - Multiples drivers - **Cons:** - Dependencia externa - Menos control - Puede no cubrir todos nuestros casos --- ## Consecuencias ### Positivas 1. **Flexibilidad:** Cambiar proveedor sin impacto en negocio 2. **Desarrollo:** MinIO local sin credenciales cloud 3. **Costos:** Migrar a R2 reduce costos ~75% 4. **Testing:** Facil mock de storage ### Negativas 1. **Complejidad:** Mantener 3 implementaciones 2. **Features especificos:** Podemos perder algunas features unicas --- ## Implementacion ### Factory ```typescript @Injectable() export class StorageFactory { create(provider: StorageProviderType): StorageProvider { switch (provider) { case 's3': return new S3StorageProvider(this.configService); case 'r2': return new R2StorageProvider(this.configService); case 'minio': return new MinIOStorageProvider(this.configService); default: throw new Error(`Unknown storage provider: ${provider}`); } } } ``` ### Provider S3 ```typescript class S3StorageProvider implements StorageProvider { private client: S3Client; constructor(config: ConfigService) { this.client = new S3Client({ region: config.get('S3_REGION'), credentials: { accessKeyId: config.get('S3_ACCESS_KEY'), secretAccessKey: config.get('S3_SECRET_KEY'), }, }); } async upload(key: string, file: Buffer, options?: UploadOptions): Promise { const command = new PutObjectCommand({ Bucket: this.bucket, Key: key, Body: file, ContentType: options?.contentType, }); await this.client.send(command); return { key, url: `https://${this.bucket}.s3.amazonaws.com/${key}`, }; } // ... otros metodos } ``` ### Uso ```typescript @Injectable() export class FileService { constructor(private readonly storageFactory: StorageFactory) {} async uploadProductImage(productId: string, file: Buffer): Promise { const storage = this.storageFactory.create(process.env.STORAGE_PROVIDER); const key = `products/${productId}/image.jpg`; const result = await storage.upload(key, file, { contentType: 'image/jpeg', }); return result.url; } } ``` --- ## Configuracion por Ambiente | Ambiente | Proveedor | Razon | |----------|-----------|-------| | Development | MinIO | Local, sin credenciales | | Staging | R2 | Costos bajos | | Production | S3 o R2 | Segun necesidad | --- ## Referencias - [AWS S3 SDK](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3/) - [Cloudflare R2](https://developers.cloudflare.com/r2/) - [MinIO](https://min.io/) - [INT-011: Storage Cloud](../02-integraciones/INT-011-storage-cloud.md) --- **Fecha decision:** 2026-01-10 **Autores:** Architecture Team