4.0 KiB
Proyectos
Cada carpeta de nivel superior es una solución/repo independiente.
Musify.WebApi/WebApi (:5111)
API REST pública (Minimal APIs, .NET 10). Es la fachada fina del sistema.
- Endpoints:
UserEndpoints,TrackEndpoints,PlayListEndpoints. - Autenticación: JWT Bearer contra Zitadel (
Authentication/), conJwtBearerEventsHandlerque sincroniza el usuario en cada token validado. CurrentUser: abstracción que se enlaza como parámetro de endpoint (IBindableFromHttpContext) y expone los claims básicos (Idcomolong?,RequiredId, nombre, etc.) sin tener que leerClaimsPrincipala mano.- Emite: presigned URLs de subida (vía
IStorageService) y stream-tickets (víaIStreamTicketService, RS256). - OpenAPI + Scalar para documentación/prueba; OAuth2 (PKCE) configurado para login desde Scalar.
- CORS totalmente abierto solo en Development (para el
player.htmly front local). - Traduce
Ardalis.Result→ HTTP enResultHttpExtensions.
Propósito/porqué: separar la cara pública (autorización + metadatos) del procesado y del servido de bytes.
MusifyBackend (Domain + Application + Infrastructure)
El núcleo, en tres proyectos (clean architecture):
Domain
Entidades (Entities/) y value objects/enums (ValueObjects/: ProcessingStatus, LifeCycleStatus, UploadIntentStatus, …). Sin dependencias de infraestructura.
Application
Casos de uso (CQRS con Mediator):
Tracks/,PlayLists/,Users/→Commands,Queries,Handlers,Responses.Contracts/→ interfaces que implementa la infraestructura (IDatabase,IStorageService,IAudioTranscoderService,IPictureService,IEventBus,IStreamTicketService).Configuration/→ opciones tipadas (Track, PlayList, ApplicationStorage, UploadIntent…) bindeadas y validadas al arranque.Shared/→ helpers transversales (StorageKey.Combine,ImageSize).Pagination/→PaginatedResponse<T>.
Porqué: la lógica de negocio no conoce EF, S3 ni RabbitMQ; solo interfaces. Reutilizable por WebApi y Worker.
Infrastructure
Implementaciones concretas:
Persistence/→Database(EF Core/Npgsql), migraciones.Services/→StorageService(AWSSDK.S3 contra SeaweedFS),AudioTranscoderService(ffmpeg →.m4a),PictureService(ImageSharp),StreamTicketService(firma RS256).MassTransit/→ consumers, activities y routing slips (ver media-processing.md).Jobs/→UploadIntentExpirationJob,TemporalUploadsCleanUpJob.
Musify.StreamingGateway/StreamingGateway (:8081)
Reverse proxy (ASP.NET + YARP) que sirve el audio (.m4a) desde SeaweedFS. Valida el stream-ticket (RS256, clave pública) y, si el objeto pedido cae bajo el prefijo autorizado, reenvía al filer.
Porqué un proyecto aparte: escala con el tráfico de bytes independientemente de la API, tiene superficie mínima (solo sabe validar un JWT y proxiar) y permite que SeaweedFS quede en red privada. Ver streaming.md.
Musify.Worker/Worker
Worker Service (host de fondo) que consume los eventos de MassTransit y ejecuta el procesado pesado: transcode de audio a .m4a (ffmpeg), generación de miniaturas (ImageSharp), transferencias de ficheros en el bucket, y los jobs de expiración/limpieza de upload intents.
Porqué aparte: el trabajo CPU/IO no debe ocurrir dentro de un request HTTP; se escala y reinicia por separado. (Antes se llamaba Musify.PictureWorker; se renombró porque hace más que imágenes.)
Raíz del workspace (no versionada)
deploy/seaweedfs/—docker-compose.yml+s3.confpara levantar SeaweedFS.player.html— consola de pruebas (un solo archivo): login con token, CRUD de playlists, añadir/quitar canciones, listar y reproducir. Ver development.md. (Pendiente: hoy usa dash.js; con el cambio a.m4adebe reproducir el fichero directo por<audio>/range.)docs/— esta documentación.