parent
fa4de8b2f6
commit
5889fad361
@ -0,0 +1,369 @@
|
||||
# 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.
|
||||
|
||||
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 |
|
||||
| `principal` | Marca de presentación |
|
||||
| `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 público y cacheable;
|
||||
- `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.
|
||||
|
||||
### 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.
|
||||
Loading…
Reference in new issue