|
|
# Plan de implementación del dominio musical
|
|
|
|
|
|
## Propósito
|
|
|
|
|
|
Este documento convierte el análisis del catálogo en un programa de cambios
|
|
|
ejecutable. La aplicación mantendrá una sola tabla `cancion` para la grabación
|
|
|
principal y sus versiones musicales, pero dejará de confundir:
|
|
|
|
|
|
- una obra y sus datos comunes;
|
|
|
- una versión musical o grabación concreta;
|
|
|
- un intérprete y su ficha pública;
|
|
|
- una representación técnica de audio para escucha, descarga o archivo.
|
|
|
|
|
|
> Estado a 11 de septiembre de 2026: 24 migraciones aplicadas y ninguna
|
|
|
> pendiente. Están implementadas las guardas, transacciones, modelo de artistas,
|
|
|
> streaming completo, ondas, fichas públicas, playlists, valoración y una parte
|
|
|
> sustancial del panel. El auditor actual encuentra 11 principales, 11 másteres,
|
|
|
> 11 escuchas y ninguna publicación sin stream. Quedan el crédito detallado en
|
|
|
> el panel, las consultas específicas por ruta y la división de los editores
|
|
|
> grandes.
|
|
|
|
|
|
### Seguimiento
|
|
|
|
|
|
| Entrega | Estado | Pendiente principal |
|
|
|
| ------- | --------- | --------------------------------------------------- |
|
|
|
| PR 1–3 | Hechas | — |
|
|
|
| PR 4 | Avanzada | Completar intérpretes y versiones reales |
|
|
|
| PR 5 | Hecha | Operación y copias de seguridad del almacén |
|
|
|
| PR 6 | En curso | Roles, instrumentos, orden y regeneración explícita |
|
|
|
| PR 7–8 | Hechas | — |
|
|
|
| PR 9 | Pendiente | Retirar el catálogo global del layout |
|
|
|
| PR 10 | En curso | Retirar último rol legado y dividir UI monolítica |
|
|
|
|
|
|
### Punto de reanudación · 11 de septiembre de 2026
|
|
|
|
|
|
La rama de trabajo es `codex/redisenio-dominio-musical`. El último bloque
|
|
|
funcional está en `bdec1e8`: el panel ya crea canciones como borrador y puede
|
|
|
procesar un máster tanto durante el alta como desde una ficha antigua sin
|
|
|
audio. La operación genera y enlaza el máster privado, la escucha MP3 completa
|
|
|
a 96 kbps y la onda de 128 puntos; no sobrescribe archivos existentes.
|
|
|
|
|
|
Estado verificado al cerrar la sesión:
|
|
|
|
|
|
- `npm run check:sitio`: 0 errores y 0 avisos;
|
|
|
- `npm run check:panel`: 0 errores y 0 avisos;
|
|
|
- `npm run test:unit -- --run`: 34 archivos y 387 pruebas correctas;
|
|
|
- builds de producción del sitio y del panel correctos;
|
|
|
- transcodificación real comprobada con un WAV temporal;
|
|
|
- 24 migraciones aplicadas, ninguna pendiente y auditoría musical íntegra.
|
|
|
|
|
|
Para probar una subida en el entorno desplegado, el panel necesita `ffmpeg` y
|
|
|
`ffprobe` en `PATH`, `BODY_SIZE_LIMIT=256M` y las mismas rutas `MEDIA_DIR`,
|
|
|
`ESCUCHA_DIR` y `ONDA_DIR` que usa el sitio. Los valores y el proxy están
|
|
|
documentados en `despliegue/con-proxy-manager.md`.
|
|
|
|
|
|
Orden acordado para continuar:
|
|
|
|
|
|
1. incorporar la portada opcional al mismo alta, con validación, recorte
|
|
|
cuadrado y registro en `medio`;
|
|
|
2. completar en el panel los créditos de interpretación —rol, instrumento,
|
|
|
acreditación y orden— y el audio propio de cada versión musical;
|
|
|
3. abordar PR 9: sustituir el catálogo completo del layout raíz por consultas
|
|
|
específicas de cada ruta;
|
|
|
4. dividir los editores monolíticos cuando esos contratos ya sean estables.
|
|
|
|
|
|
El trabajo será incremental. Las migraciones serán aditivas hasta que las
|
|
|
lecturas nuevas estén verificadas; ninguna columna ni relación actual se
|
|
|
retirará en la misma entrega que introduce su sustituta.
|
|
|
|
|
|
## Decisiones cerradas
|
|
|
|
|
|
### Canción y versiones
|
|
|
|
|
|
Cada fila de `cancion` es una versión musical reproducible. La principal tiene
|
|
|
`version_de_id = null`; una versión alternativa apunta directamente a la
|
|
|
principal.
|
|
|
|
|
|
La base debe garantizar que:
|
|
|
|
|
|
- una versión no apunta a sí misma;
|
|
|
- una versión solo apunta a una principal;
|
|
|
- no hay cadenas de versiones ni ciclos;
|
|
|
- solo una principal puede ponerse a la venta;
|
|
|
- comprar la principal da derecho a descargar sus versiones publicadas;
|
|
|
- `version_codigo` es único dentro de una principal.
|
|
|
|
|
|
Los datos comunes de la composición —ISWC, autoría y reparto— se asocian a la
|
|
|
principal. Los datos de grabación —ISRC, intérpretes, audio, duración y fecha—
|
|
|
pertenecen a cada fila concreta.
|
|
|
|
|
|
### Persona y artista
|
|
|
|
|
|
`persona` seguirá representando personas físicas, autoría, datos legales e IPI.
|
|
|
No representará grupos ni proyectos artísticos.
|
|
|
|
|
|
Se añadirá `artista`, que representa la identidad pública acreditada. Puede ser
|
|
|
una persona, un grupo o un proyecto. Una persona puede tener más de una
|
|
|
identidad artística y un grupo puede relacionarse con varias personas.
|
|
|
|
|
|
El identificador interno, el código de negocio y la URL tienen funciones
|
|
|
distintas:
|
|
|
|
|
|
- `id`: UUID opaco usado por claves foráneas;
|
|
|
- `codigo`: identificador estable de negocio, por ejemplo `ART-000123`;
|
|
|
- `slug`: dirección pública modificable.
|
|
|
|
|
|
### Versiones musicales y calidades de audio
|
|
|
|
|
|
Una versión orquestal, una maqueta y una toma en directo son filas distintas de
|
|
|
`cancion`. MP3 a 128 kbps, MP3 a 320 kbps y WAV son representaciones técnicas de
|
|
|
la misma fila y no crean canciones nuevas.
|
|
|
|
|
|
La escucha pública será completa en calidad web. La compra entregará archivos
|
|
|
de mayor calidad y, cuando corresponda, todas las versiones incluidas. No se
|
|
|
intentará presentar el streaming público como un archivo imposible de copiar:
|
|
|
la autorización protege la descarga de alta calidad, no el contenido que el
|
|
|
navegador necesariamente recibe para reproducir.
|
|
|
|
|
|
## Modelo de datos objetivo
|
|
|
|
|
|
### `artista`
|
|
|
|
|
|
| Columna | Regla |
|
|
|
| ------------------- | -------------------------------------------------------- |
|
|
|
| `id` | UUID, clave primaria |
|
|
|
| `codigo` | Único, inmutable |
|
|
|
| `slug` | Único, usado en URL |
|
|
|
| `tipo` | `persona`, `grupo` o `proyecto` |
|
|
|
| `nombre` | Nombre artístico visible |
|
|
|
| `descripcion_corta` | Texto para tarjetas y resultados |
|
|
|
| `biografia` | Markdown para la ficha |
|
|
|
| `imagen_id` | FK a `medio`, borrado con `set null` |
|
|
|
| `pais_codigo` | FK opcional a `pais` |
|
|
|
| `lugar_origen` | Texto opcional |
|
|
|
| `fecha_inicio` | Fecha o año, por decidir tras inventariar los datos |
|
|
|
| `fecha_fin` | Opcional |
|
|
|
| `sitio_web` | URL opcional |
|
|
|
| `estado` | `borrador`, `publicado` o `retirado` |
|
|
|
| auditoría | procedencia, revisión, creación y actualización actuales |
|
|
|
|
|
|
No se añadirá `nombre_legal` ni `ipi` a `artista`; esos datos pertenecen a
|
|
|
`persona`.
|
|
|
|
|
|
### `artista_persona`
|
|
|
|
|
|
Relaciona una identidad artística con personas físicas.
|
|
|
|
|
|
| Columna | Regla |
|
|
|
| ------------ | ----------------------------------- |
|
|
|
| `artista_id` | FK a `artista` |
|
|
|
| `persona_id` | FK a `persona` |
|
|
|
| `relacion` | `identidad`, `miembro` o `fundador` |
|
|
|
| `desde` | Fecha o año opcional |
|
|
|
| `hasta` | Fecha o año opcional |
|
|
|
| `orden` | Orden visible |
|
|
|
|
|
|
La clave primaria incluirá artista, persona y relación. Una guarda comprobará
|
|
|
que el período no termina antes de empezar.
|
|
|
|
|
|
### `artista_identificador`
|
|
|
|
|
|
Guarda identificadores externos sin crear una columna nueva por plataforma.
|
|
|
|
|
|
| Columna | Regla |
|
|
|
| ------------ | ----------------------------------------------------- |
|
|
|
| `artista_id` | FK a `artista` |
|
|
|
| `sistema` | `spotify`, `apple_music`, `musicbrainz`, `isni`, etc. |
|
|
|
| `valor` | Identificador en ese sistema |
|
|
|
|
|
|
Serán únicos tanto `(artista_id, sistema)` como `(sistema, valor)` cuando el
|
|
|
sistema garantice unicidad global.
|
|
|
|
|
|
### `cancion_interprete`
|
|
|
|
|
|
Relaciona un artista con una versión musical concreta.
|
|
|
|
|
|
| Columna | Regla |
|
|
|
| ----------------- | --------------------------------------------------- |
|
|
|
| `cancion_id` | FK a la fila concreta de `cancion` |
|
|
|
| `artista_id` | FK a `artista` |
|
|
|
| `rol` | `principal`, `invitado`, `coros` o `instrumentista` |
|
|
|
| `instrumento` | Opcional |
|
|
|
| `acreditado_como` | Nombre histórico de ese crédito, opcional |
|
|
|
| `orden` | Orden del crédito |
|
|
|
|
|
|
La relación actual `cancion_persona` conservará temporalmente letra, música,
|
|
|
arreglos y producción. El rol `interprete` se retirará solo después de comprobar
|
|
|
la paridad de datos.
|
|
|
|
|
|
### `cancion_audio`
|
|
|
|
|
|
Relaciona cada versión con sus representaciones técnicas.
|
|
|
|
|
|
| Columna | Regla |
|
|
|
| --------------- | ----------------------------------------- |
|
|
|
| `cancion_id` | FK a `cancion` |
|
|
|
| `medio_id` | FK a `medio` |
|
|
|
| `uso` | `stream`, `descarga` o `master` |
|
|
|
| `formato` | `mp3`, `aac`, `opus`, `flac`, `wav`, etc. |
|
|
|
| `bitrate_kbps` | Opcional para formatos con pérdida |
|
|
|
| `frecuencia_hz` | Opcional |
|
|
|
| `bits_muestra` | Opcional |
|
|
|
| `canales` | Opcional |
|
|
|
| `orden` | Preferencia dentro de un mismo uso |
|
|
|
|
|
|
`medio.publico` y `uso` deben ser coherentes:
|
|
|
|
|
|
- `stream`: medio privado, entregado completo y con autorización según
|
|
|
`cancion.acceso`;
|
|
|
- `descarga`: medio privado, entregado solo con autorización;
|
|
|
- `master`: medio privado y nunca entregado por la web pública.
|
|
|
|
|
|
Una restricción impedirá repetir la misma combinación de canción, uso y
|
|
|
formato. Si se necesitan dos codificaciones equivalentes, el modelo se ampliará
|
|
|
con un identificador de perfil explícito, no relajando la unicidad sin motivo.
|
|
|
|
|
|
### Ajustes en `cancion`
|
|
|
|
|
|
Se añadirá `codigo`, único e inmutable. Se revisarán las columnas actuales con
|
|
|
estas reglas:
|
|
|
|
|
|
- `isrc` pertenece a cada versión;
|
|
|
- `iswc`, autoría y reparto pertenecen a la principal;
|
|
|
- `audio_id` y `muestra_id` quedan obsoletos tras poblar `cancion_audio`;
|
|
|
- `ala_venta` solo puede ser cierto en una principal;
|
|
|
- una versión puede tener intérpretes, audio, portada y duración propios;
|
|
|
- una versión sin letra propia puede usar la de la principal en el read model,
|
|
|
sin copiarla al guardar.
|
|
|
|
|
|
No se moverá todavía `album_id` a una tabla puente. Se documenta como evolución
|
|
|
posterior si una misma grabación debe aparecer en varias ediciones.
|
|
|
|
|
|
## Contratos de aplicación
|
|
|
|
|
|
Los intérpretes dejan de ser `string[]`. Las lecturas públicas usarán objetos
|
|
|
tipados:
|
|
|
|
|
|
```ts
|
|
|
interface InterpreteResumen {
|
|
|
id: string;
|
|
|
codigo: string;
|
|
|
slug: string;
|
|
|
nombre: string;
|
|
|
tipo: 'persona' | 'grupo' | 'proyecto';
|
|
|
imagen?: string;
|
|
|
rol: 'principal' | 'invitado' | 'coros' | 'instrumentista';
|
|
|
instrumento?: string;
|
|
|
}
|
|
|
```
|
|
|
|
|
|
Se crearán read models independientes:
|
|
|
|
|
|
- `CancionPublicaReadModel`;
|
|
|
- `FichaArtistaReadModel`;
|
|
|
- `ListadoArtistasReadModel`;
|
|
|
- `AudioReproducibleReadModel`;
|
|
|
- `DescargaCompradaReadModel`.
|
|
|
|
|
|
La ficha de canción no resolverá biografías completas. Solo recibe el resumen y
|
|
|
enlaza a `/interpretes/[slug]`; la ficha del artista carga biografía,
|
|
|
identificadores públicos y discografía.
|
|
|
|
|
|
## Programa de entregas
|
|
|
|
|
|
### PR 1 · Guardas de publicación
|
|
|
|
|
|
1. Centralizar el predicado de contenido público.
|
|
|
2. Aplicarlo a catálogo, canciones, álbumes, estilos, géneros, sitemap y SEO.
|
|
|
3. Separar lectura pública de lectura autorizada para canciones retiradas.
|
|
|
4. Añadir integración PostgreSQL para borrador, publicado y retirado.
|
|
|
|
|
|
No depende del nuevo modelo y evita publicar accidentalmente datos durante la
|
|
|
migración.
|
|
|
|
|
|
### PR 2 · Autenticación y comercio atómicos
|
|
|
|
|
|
1. Hacer atómicos el límite de peticiones y el consumo de OTP.
|
|
|
2. Añadir unicidad de carrito por usuario, fusionando duplicados existentes.
|
|
|
3. Crear pedido y líneas en una transacción.
|
|
|
4. Finalizar pedidos con transición condicional pendiente → pagado.
|
|
|
5. Registrar el inicio autorizado de una descarga o ajustar su semántica.
|
|
|
|
|
|
### PR 3 · Esquema aditivo de artistas y audio
|
|
|
|
|
|
1. Sincronizar primero el journal de Drizzle con `0011` y `0012`.
|
|
|
2. Añadir `artista`, `artista_persona`, `artista_identificador`,
|
|
|
`cancion_interprete` y `cancion_audio`.
|
|
|
3. Añadir `cancion.codigo` y las restricciones de versiones.
|
|
|
4. Añadir `CHECK` reales para los vocabularios cerrados.
|
|
|
5. Mantener intactas las columnas y relaciones antiguas.
|
|
|
|
|
|
La migración debe ejecutarse sobre una copia de producción antes de aplicarse al
|
|
|
entorno real.
|
|
|
|
|
|
### PR 4 · Inventario y migración de datos
|
|
|
|
|
|
El script de migración será repetible y producirá un informe antes de escribir.
|
|
|
|
|
|
1. Inventariar nombres usados como intérprete.
|
|
|
2. Normalizar mayúsculas, espacios y variantes obvias sin fusionar por heurística.
|
|
|
3. Presentar colisiones para decisión manual.
|
|
|
4. Crear un `artista` por identidad confirmada.
|
|
|
5. Relacionar personas físicas conocidas mediante `artista_persona`.
|
|
|
6. Migrar `cancion_persona(rol = interprete)` a `cancion_interprete`.
|
|
|
7. Crear códigos estables para canciones y artistas.
|
|
|
8. Convertir el audio completo actual en representación `master` o `descarga`
|
|
|
según el formato real.
|
|
|
9. Marcar las muestras recortadas como legado; no confundirlas con el nuevo
|
|
|
streaming completo.
|
|
|
|
|
|
El informe debe comparar canciones, versiones, intérpretes y archivos antes y
|
|
|
después, y detenerse ante cualquier huérfano.
|
|
|
|
|
|
### PR 5 · Pipeline de audio completo
|
|
|
|
|
|
1. Recibir o localizar el master privado.
|
|
|
2. Obtener duración, códec, frecuencia y canales mediante `ffprobe`.
|
|
|
3. Calcular la huella antes de generar derivados.
|
|
|
4. Generar la calidad web completa con un perfil versionado.
|
|
|
5. Generar las calidades de descarga acordadas.
|
|
|
6. Insertar todos los medios y relaciones en una transacción.
|
|
|
7. No permitir publicar una canción sin una representación `stream` válida.
|
|
|
8. Servir audio con `Range`, tipo MIME, `ETag` y caché coherentes.
|
|
|
|
|
|
El perfil inicial se decidirá escuchando material real. Como punto de partida:
|
|
|
stream MP3/AAC entre 96 y 128 kbps y descarga MP3 320 kbps; WAV o FLAC se
|
|
|
conservarán como master y solo se ofrecerán si forman parte del producto.
|
|
|
|
|
|
La primera automatización interactiva ya está disponible en el panel: crea la
|
|
|
canción como borrador y, si recibe un máster, ejecuta validación, `ffprobe`,
|
|
|
transcodificación MP3 a 96 kbps, forma de onda de 128 puntos y alta de medios.
|
|
|
También puede completar canciones antiguas que aún no tienen audio. La
|
|
|
operación no sobrescribe archivos existentes.
|
|
|
|
|
|
### PR 6 · Panel de artistas, créditos y audio
|
|
|
|
|
|
1. CRUD de artistas con imagen, descripción, biografía, país y estado.
|
|
|
2. Selector de intérpretes en cada versión musical.
|
|
|
3. Edición de rol, instrumento, acreditación y orden.
|
|
|
4. Vista de las representaciones de audio y su estado de procesamiento.
|
|
|
5. Acción explícita para regenerar derivados desde el master.
|
|
|
6. Bloqueo de publicación con errores accionables.
|
|
|
|
|
|
El panel no aceptará nombres libres como intérpretes. Permitirá crear un artista
|
|
|
desde el selector sin abandonar la canción.
|
|
|
|
|
|
### PR 7 · Lecturas públicas y fichas
|
|
|
|
|
|
1. Cambiar `Cancion.interpretes` de nombres a objetos.
|
|
|
2. Crear `/interpretes` y `/interpretes/[slug]`.
|
|
|
3. Mostrar imagen, descripción, biografía y discografía.
|
|
|
4. Enlazar los créditos de canciones y álbumes con la ficha correspondiente.
|
|
|
5. Incluir únicamente artistas publicados en rutas públicas y sitemap.
|
|
|
6. Mantener acreditaciones históricas aunque cambie el nombre actual del artista.
|
|
|
|
|
|
### PR 8 · Reproductor y compra
|
|
|
|
|
|
1. Sustituir la muestra recortada por la representación `stream` completa.
|
|
|
2. Actualizar cola, duración, textos y estados de error.
|
|
|
3. Autorizar descargas de representaciones `descarga` de la principal y sus
|
|
|
versiones publicadas incluidas.
|
|
|
4. Impedir que URLs privadas viajen en los datos de página.
|
|
|
5. Actualizar condiciones de venta y privacidad antes de producción.
|
|
|
|
|
|
### PR 9 · Consultas, caché y layout
|
|
|
|
|
|
1. Eliminar el catálogo entero del layout raíz.
|
|
|
2. Crear read models específicos por ruta.
|
|
|
3. Paralelizar las consultas transversales restantes.
|
|
|
4. Retirar la invalidación de memoria entre panel y sitio.
|
|
|
5. Medir antes de introducir una caché compartida.
|
|
|
|
|
|
### PR 10 · Retirada del legado y división de UI
|
|
|
|
|
|
1. Retirar `cancion_persona.rol = interprete` tras comprobar paridad.
|
|
|
2. Retirar `audio_id` y `muestra_id` tras comprobar todos los medios.
|
|
|
3. Mover el código Markdown restante a importadores o eliminarlo.
|
|
|
4. Actualizar README, `.env.example` y modelo de datos.
|
|
|
5. Dividir `Capitulo.svelte` y los editores grandes del panel por responsabilidad.
|
|
|
6. Centralizar plataformas, formatos, etiquetas y políticas duplicadas.
|
|
|
|
|
|
## Estrategia de despliegue y reversión
|
|
|
|
|
|
1. Copia de seguridad y restauración ensayada antes de migrar datos.
|
|
|
2. Migraciones aditivas compatibles con la versión anterior del servidor.
|
|
|
3. Backfill separado, repetible y con modo de solo informe.
|
|
|
4. Activación de lecturas nuevas mediante una única configuración temporal.
|
|
|
5. Comparación de lecturas antigua y nueva en pruebas y entorno de ensayo.
|
|
|
6. Despliegue del código nuevo antes de retirar columnas antiguas.
|
|
|
7. Retirada destructiva en una migración posterior, con respaldo confirmado.
|
|
|
|
|
|
La reversión durante la fase aditiva consiste en volver al servidor anterior;
|
|
|
las tablas nuevas pueden permanecer. Después de la retirada destructiva, la
|
|
|
reversión requiere restaurar la copia, por lo que esa entrega tendrá una ventana
|
|
|
de despliegue explícita.
|
|
|
|
|
|
## Verificación mínima por entrega
|
|
|
|
|
|
```text
|
|
|
npm run check
|
|
|
npm run lint
|
|
|
npm run test:unit -- --run
|
|
|
npm run build
|
|
|
npm run build:panel
|
|
|
pruebas de integración contra PostgreSQL aislado
|
|
|
E2E de los flujos modificados
|
|
|
```
|
|
|
|
|
|
Pruebas específicas obligatorias:
|
|
|
|
|
|
- un borrador nunca aparece públicamente;
|
|
|
- dos consumos simultáneos de OTP solo producen un éxito;
|
|
|
- dos confirmaciones de Stripe solo finalizan un pedido una vez;
|
|
|
- cada versión devuelve sus propios intérpretes;
|
|
|
- una compra de la principal autoriza las versiones incluidas;
|
|
|
- el streaming reproduce la duración completa;
|
|
|
- el navegador nunca recibe la clave del master o de la descarga privada;
|
|
|
- un artista retirado conserva los créditos históricos sin tener ficha pública;
|
|
|
- el backfill conserva el número de canciones, versiones y relaciones válidas.
|
|
|
|
|
|
## Criterio de finalización
|
|
|
|
|
|
El programa se considera cerrado cuando el catálogo público usa exclusivamente
|
|
|
los nuevos read models, los intérpretes son entidades administrables y
|
|
|
enlazables, el streaming completo se genera desde masters privados, las compras
|
|
|
entregan representaciones de alta calidad, no quedan lecturas productivas del
|
|
|
modelo legado y todos los checks, integración y E2E pasan en CI.
|
|
|
|
|
|
## Ampliación: comercio extensible
|
|
|
|
|
|
La revisión del 12 de septiembre de 2026 detectó que el cierre por packs
|
|
|
exactos impedía comprar libremente. La implementación asociada sustituye esa
|
|
|
regla por packs de hasta diez, calculados automáticamente, y separa selección,
|
|
|
líneas facturadas y derechos entregados.
|
|
|
|
|
|
También queda preparada la base común para libros, partituras, MIDI, stems,
|
|
|
servicios y niveles de suscripción. La decisión y los límites de esta fase se
|
|
|
documentan en `docs/arquitectura-comercio-2026-09-12.md`.
|