The root README was a design handoff for a prototype that is not in this repo, web-player/README.md was the sv template, and deploy/README.md only covered development. Replace all three and document the production deploy: its prerequisites, what up.sh does and why nginx sits in front. The docs under docs/ still used the pre-monorepo project paths, Ardalis.Result instead of ErrorOr and the player.html test console that no longer exists.
4.0 KiB
Proyectos
Los seis proyectos .NET viven en backend/ (solución Musify.slnx); el cliente
web en web-player/.
Musify.Api (: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 front local).
- Traduce
ErrorOr→ HTTP enResultHttpExtensions.
Propósito/porqué: separar la cara pública (autorización + metadatos) del procesado y del servido de bytes.
Musify.Domain + Musify.Application + Musify.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 la API y el 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 (: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 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.)
web-player (:5173 en dev, :3000 en contenedor)
Cliente web (SvelteKit 2 + Svelte 5 + Tailwind 4). La sesión OIDC vive en el servidor (cookie cifrada); las llamadas al backend salen del servidor con el access token, y las subidas se hacen contra las URLs prefirmadas de S3.
Otras carpetas
deploy/— stacks de Docker Compose (dev y prod) y los scripts de arranque, migraciones y provisioning. Ver ../deploy/README.md.docs/— esta documentación.