# MusifyBackend — Resumen de cambios (2026-05-14) Este documento resume **todos los cambios aplicados hasta ahora** en la rama `master` durante esta iteración. > Nota: El proyecto compila en `Release` al cierre de estos cambios. --- ## 1) Mensajería robusta: MassTransit + EF Outbox **Objetivo**: hacer la publicación de eventos confiable y transaccional (DB + mensajes) y tolerar redelivery en consumidores. ### Cambios principales - Se integró **MassTransit EntityFramework Outbox** con PostgreSQL (`UsePostgres` + `UseBusOutbox`). - Se añadieron entidades/tablas de **Inbox/Outbox** en el `DbContext`. - Se generó y añadió una **migración** para las tablas de outbox/inbox. - Se ajustó la configuración de endpoints para aplicar: - **Retry** (exponential backoff) - **Idempotencia** en consumo usando `UseEntityFrameworkOutbox()` - Se ajustó el orden de operaciones para el patrón outbox: **publicar evento y luego `SaveChanges`**. ### Archivos involucrados (principalmente) - `Infrastructure/MassTransit/DependencyInjection/MassTransitDependencyInjection.cs` - `Infrastructure/MassTransit/DependencyInjection/MassTransitDependencyInjection.Endpoints.cs` - `Infrastructure/Persistence/Database.cs` - `Infrastructure/Persistence/Migrations/20260514095113_AddMassTransitOutbox.cs` - `Application/Abstractions/Infrastructure/IEventBus.cs` - `Infrastructure/MassTransit/EventBus/MassTransitEventBus.cs` --- ## 2) Workflows: Courier RoutingSlip para imágenes y audio **Objetivo**: mantener el pipeline asíncrono (descarga, resize/transcode, upload, update de entidades) con reintentos e idempotencia. ### Fix importante en workflow de imágenes - Se corrigió el nombre de actividad del paso de **Upload del tamaño Medium** (antes duplicaba el nombre de `ResizeMedium`). Archivos: - `Infrastructure/MassTransit/RoutingSlip/Builders/PictureWorkflowRoutingSlipBuilder.cs` - `Infrastructure/MassTransit/RoutingSlip/ActivityNames.cs` ### Fix importante en compensación de uploads - `UploadFileToBucketActivity` ahora registra correctamente el **object key completo** (ruta + filename) para que la compensación borre el objeto correcto. Archivo: - `Infrastructure/MassTransit/Activities/Files/UploadFileToBucketActivity.cs` --- ## 3) Uploads (Opción B): Presigned PUT URL + Create/Update con nombres **Objetivo**: separar la subida de binarios (S3) de la operación de dominio (Create/Update), evitando rollbacks complejos y haciendo el flujo más robusto. ### Endpoint/Commands añadidos (request presigned URL) - Playlist picture: - `Application/PlayLists/Commands/RequestPlayListPictureUploadCommand.cs` - `Application/PlayLists/Handlers/RequestPlayListPictureUploadCommandHandler.cs` - `Application/PlayLists/Responses/PlayListPictureUploadResponse.cs` - Track picture + audio: - `Application/Tracks/Commands/RequestTrackUploadUrlsCommand.cs` - `Application/Tracks/Handler/RequestTrackUploadUrlsCommandHandler.cs` - `Application/Tracks/Responses/TrackUploadUrlsResponse.cs` ### Storage: presigned PUT - Se añadió soporte para generar **presigned PUT URLs**: - `Application/Abstractions/Infrastructure/IStorageService.cs` - `Infrastructure/Services/StorageService.cs` (`GetUploadUrlAsync`) --- ## 4) Limpieza: eliminar V1 y normalizar nombres (V2 → “normal”) **Objetivo**: eliminar comandos/handlers “V1” (subida directa por stream/multipart) y dejar un único set de comandos “normales” con el contrato final. ### Resultado - `CreatePlayListCommand`, `UpdatePlayListCommand` y `CreateTrackCommand` quedaron con el contrato nuevo (nombres/metadata, no streams). - Se eliminaron archivos `*V2*` ya innecesarios. Archivos clave: - `Application/PlayLists/Commands/CreatePlayListCommand.cs` - `Application/PlayLists/Handlers/CreatePlayListCommandHandler.cs` - `Application/PlayLists/Commands/UpdatePlayListCommand.cs` - `Application/PlayLists/Handlers/UpdatePlayListCommandHandler.cs` - `Application/Tracks/Commands/CreateTrackCommand.cs` - `Application/Tracks/Handler/CreateTrackCommandHandler.cs` --- ## 5) Prefijo de seguridad: `uploads/{userId}/...` para originales **Objetivo**: reducir superficie (y colisiones) haciendo que los objetos originales queden naturalmente “namespaced” por usuario. ### Cambios - Las **keys de originales** (playlist original picture, track original picture, track original audio) ahora se generan bajo: - `uploads/{userId}/...` - Se añadieron overloads de rutas para construir keys con `userId`. - Los handlers de request presigned URL ahora generan keys usando el prefijo con `userId`. - Los eventos de workflows (sourceKey) se publican con la key prefijada. - El borrado de playlist borra la key original prefijada. - El borrado de track (`DeleteTrackActivity`) borra originales usando el `userId` presente en `DeleteTrackArguments`. Archivos: - `Application/Configuration/PlayListConfiguration.cs` - `Application/Configuration/TrackConfiguration.cs` - `Application/PlayLists/Handlers/RequestPlayListPictureUploadCommandHandler.cs` - `Application/Tracks/Handler/RequestTrackUploadUrlsCommandHandler.cs` - `Application/PlayLists/Handlers/CreatePlayListCommandHandler.cs` - `Application/PlayLists/Handlers/UpdatePlayListCommandHandler.cs` - `Application/Tracks/Handler/CreateTrackCommandHandler.cs` - `Application/PlayLists/Handlers/DeletePlayListCommandHandler.cs` - `Infrastructure/MassTransit/Activities/Tracks/DeleteTrackActivity.cs` --- ## 6) Normalización de separadores en keys S3 (evitar `\\` en Windows) **Objetivo**: evitar que `Path.Combine` introduzca separadores `\\` en keys S3 (lo cual es incorrecto/inesperado en S3, y rompe interoperabilidad). ### Cambios - Se reemplazaron combinaciones de keys que usaban `Path.Combine` por joins con `/` en puntos críticos. Archivos: - `Application/Configuration/PlayListConfiguration.cs` - `Application/Configuration/TrackConfiguration.cs` - `Infrastructure/MassTransit/Activities/Files/UploadFileToBucketActivity.cs` - `Infrastructure/Services/StorageService.cs` --- ## 7) Validaciones en Application eliminadas (delegadas a API) **Objetivo**: evitar duplicar validaciones de formato (extensiones/strings) si la capa API ya se encarga. ### Cambios - Se eliminó el helper de validación creado inicialmente y los checks en handlers. Archivos: - Eliminado: `Application/Validation/UploadObjectNameValidator.cs` - Ajustados: - `Application/PlayLists/Handlers/CreatePlayListCommandHandler.cs` - `Application/PlayLists/Handlers/UpdatePlayListCommandHandler.cs` - `Application/Tracks/Handler/CreateTrackCommandHandler.cs` --- ## 8) Documento de mitigaciones (presigned uploads) Se añadió documentación de hardening/mitigaciones contra abuso/spam en endpoints presigned. Archivo: - `docs/presigned-upload-hardening.md` --- ## 9) Notas de compatibilidad / impacto - Este cambio **rompe compatibilidad** con la API anterior si existían endpoints que aceptaban multipart/streams para Create/Update (ahora se espera el flujo presigned y luego Create/Update con nombres). - Los objetos originales ahora viven bajo `uploads/{userId}/...`. Objetos antiguos fuera de ese prefijo pueden quedar huérfanos si ya existían de antes. --- ## 10) Estado final - `dotnet build MusifyBackend.slnx -c Release` ✅