Skip to content

[F2-05] Almacenamiento intercambiable: disco local y S3-compatible #27

Open

Description

@JCCG-code

Fase: F2 · Tamaño: M · Depende de: #23 (F1-03), #18 (F0-07)

Objetivo

Guardar los ficheros generados en disco local en desarrollo y en cualquier almacenamiento compatible con S3 en producción (Cloudflare R2, MinIO, AWS), sustituyendo a Google Cloud Storage y sin atarse a un hosting (D-10 en #1).

Alcance

  • Interfaz StorageDriver: put, getStream, downloadToFile, head, delete, deletePrefix, signedUrl({ expiresInSec, downloadName }).
  • LocalDiskDriver: raíz ./.data/storage; URLs firmadas con HMAC servidas por la API en GET /api/v1/files/*, con soporte de Range (para poder saltar en el reproductor).
  • S3Driver con @aws-sdk/client-s3 + @aws-sdk/s3-request-presigner; bucket privado; downloadName vía ResponseContentDisposition.
  • Selección con STORAGE_DRIVER=local|s3 y variables S3_ENDPOINT, S3_REGION, S3_BUCKET, S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY, S3_FORCE_PATH_STYLE.
  • Esquema de claves: users/{userId}/projects/{projectId}/{kind}/{assetId}.{ext}. En base de datos se guardan claves, nunca URLs.
  • deletePrefix se niega a borrar cualquier prefijo que no sea users/{id}/projects/{id}/.

Criterios de aceptación

  • La misma suite de tests pasa contra LocalDiskDriver y contra S3Driver apuntando al MinIO de docker-compose.
  • Test: una URL firmada caducada devuelve 403; una válida devuelve 200; con Range: bytes=0-99 devuelve 206 con 100 bytes.
  • Test: deletePrefix('audio/') lanza error sin borrar nada.
  • Test: signedUrl con downloadName: 'mi-video.mp4' hace que la descarga llegue con ese nombre.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions