159 lines
7.6 KiB
Markdown
159 lines
7.6 KiB
Markdown
# Musify — Guía de páginas
|
|
|
|
Documento vivo de qué debe contener cada página del frontend web. Sirve como mapa
|
|
para priorizar features. El sistema de diseño (tokens, recetas, componentes) vive en
|
|
el skill `musify-web`; aquí describimos **contenido y estructura**, no estilos.
|
|
|
|
Leyenda de estado: ✅ hecho · 🟡 parcial / maqueta · ⬜ pendiente.
|
|
|
|
> **Nota (rediseño app):** se está portando el prototipo `Musify.dc.html` (app: sidebar +
|
|
> vistas + player persistente con acento dinámico por pista). La landing de marketing se
|
|
> eliminó. Las secciones de abajo describen el diseño anterior y quedan pendientes de
|
|
> actualizar a las vistas de la app (Inicio, Buscar, Biblioteca, Subir, Importar, Descargas,
|
|
> Playlists). El **player** ya está hecho por componentes en `$lib/components/player/` con el
|
|
> tema en `$lib/theme/` (`theme.css` paleta + `color.ts` acento/gradiente).
|
|
|
|
## Inicio (app) `/` 🟡
|
|
|
|
- **Hero**: saludo + "Tu música. Sin límites." con color-wash del hue de la pista actual.
|
|
- **Acceso rápido = escuchado recientemente** (`player.recentlyPlayed`, hoy en cliente).
|
|
Estado vacío con icono + CTA «Explorar».
|
|
- **Tus playlists**: tarjetas mosaico de las playlists (hoy datos de muestra). Estado vacío.
|
|
|
|
### Backend pendiente (ASP.NET) para Inicio
|
|
|
|
- **Escuchado recientemente**: registrar reproducciones por usuario (tabla de historial:
|
|
`userId`, `trackId`, `playedAt`) y exponer `GET /me/recently-played?limit=` (o
|
|
`/users/{id}/recently-played`) devolviendo pistas ordenadas por `playedAt` desc, sin
|
|
duplicados. El front lo cargaría en un `load` y lo pasaría al store en vez de `recentlyPlayed`.
|
|
- **Playlists por última escucha**: añadir `lastPlayedAt` a la playlist (hoy el schema solo
|
|
tiene `createdAt`/`updatedAt`) y permitir ordenar `GET /playlists/users/{userId}` por ese
|
|
campo (p. ej. `?sort=lastPlayed`), para mostrar «tus últimas escuchadas».
|
|
- Las pistas necesitarán **artista** y un **color/hue** (o portada real de la que extraerlo)
|
|
para el arte y el acento dinámico; hoy `TrackApplicationResponse` no trae artista ni color.
|
|
|
|
## Estructura de rutas
|
|
|
|
Rutas agrupadas para separar lo público de lo autenticado (los grupos no cambian la URL):
|
|
|
|
```
|
|
src/routes/
|
|
(marketing)/ Público, sin sesión obligatoria
|
|
+page.svelte / Landing ✅
|
|
(app)/ Experiencia de la app
|
|
explore/ /explore Explorar / buscar ✅
|
|
upload/ /upload Subir música 🟡 maqueta
|
|
library/ /library Tu biblioteca ⬜
|
|
playlists/ /playlists Tus playlists ⬜
|
|
[id]/ /playlists/:id Detalle playlist ⬜
|
|
login logout auth/callback Auth (endpoints) ✅
|
|
api/tracks/[id]/stream Proxy de stream ✅
|
|
```
|
|
|
|
Componentes globales (en todas las páginas): **Navbar**, **Footer** y **PlayerBar**
|
|
(barra de reproducción fija, aparece al reproducir).
|
|
|
|
---
|
|
|
|
## 1. Landing `/` ✅ (marketing)
|
|
|
|
Página de entrada para no autenticados. Vender el producto y llevar a registro/explorar.
|
|
|
|
- **Hero**: badge de estado (beta), título, subtítulo, CTAs primario (Empezar gratis →
|
|
registro) y secundario (Explorar canciones).
|
|
- **Features**: 3 cards (escuchar, playlists, subir).
|
|
- **Pendiente sugerido**: sección de capturas/demo, prueba social, FAQ corta.
|
|
|
|
## 2. Login / Auth ✅ (endpoints)
|
|
|
|
No es una página visual propia: `/login` inicia el flujo OIDC de Zitadel y redirige.
|
|
`?mode=register` arranca en registro; `?returnTo=` vuelve a la ruta pedida tras entrar.
|
|
`/logout` cierra sesión. `/auth/callback` intercambia el código y crea la cookie
|
|
cifrada `mf_session`. La UI de credenciales la sirve Zitadel, no Musify.
|
|
|
|
## 3. Explorar / Buscar `/explore` ✅ (app)
|
|
|
|
Descubrimiento y búsqueda de canciones del catálogo.
|
|
|
|
- **Buscador**: input de texto (`?q=`) que filtra por nombre en el backend.
|
|
- **Contador de resultados** y **grid de tracks** (2→4 columnas): portada, título, fecha,
|
|
botón play/pausa en hover que encola y reproduce vía el player global.
|
|
- **Paginación** anterior/siguiente (`?page=`, 24 por página).
|
|
- **Estado vacío**: sin resultados / catálogo vacío.
|
|
- **Pendiente sugerido**: filtros (más recientes, por usuario), skeletons de carga,
|
|
portada real del track (hoy la API de listado no devuelve la key de imagen).
|
|
|
|
## 4. Subir música `/upload` 🟡 maqueta (app)
|
|
|
|
Alta de una canción nueva. Flujo real de backend (para cuando se cablee):
|
|
1. `POST /tracks/upload-urls` → URLs presignadas para portada y audio + `intentId`s.
|
|
2. `PUT` de cada archivo a su URL presignada (subida directa al almacenamiento).
|
|
3. `POST /tracks` con `title`, `pictureIntentId`, `audioIntentId`.
|
|
4. El backend procesa el audio (transcodifica a DASH) de forma asíncrona.
|
|
|
|
Contenido de la página:
|
|
|
|
- **Zona de audio**: drag & drop o selector; muestra nombre y tamaño del archivo, validación
|
|
de tipo (audio) y tamaño.
|
|
- **Portada**: selector de imagen con vista previa cuadrada.
|
|
- **Metadatos**: título (obligatorio). Espacio para futuros campos (descripción, etc.).
|
|
- **Pipeline visible**: pasos Subir → Procesar → Publicar con su estado.
|
|
- **Barra de progreso** de subida y estado de procesado.
|
|
- **Estados**: vacío, archivo seleccionado, subiendo, procesando, publicado, error.
|
|
- **Requiere sesión** (al cablear: redirigir a `/login?returnTo=/upload`).
|
|
|
|
## 5. Tu biblioteca `/library` ⬜ (app)
|
|
|
|
Panel personal del usuario autenticado: lo suyo en un sitio.
|
|
|
|
- **Tabs / secciones**: «Tus canciones» (`GET /tracks/users/{userId}`) y «Tus playlists»
|
|
(`GET /playlists/users/{userId}`).
|
|
- **Tus canciones**: lista con play, y acciones de gestión (borrar `DELETE /tracks/{id}`,
|
|
añadir a playlist).
|
|
- **Tus playlists**: grid de portadas + botón «Crear playlist».
|
|
- **Estado vacío** con CTA a subir / crear.
|
|
- **Requiere sesión**.
|
|
|
|
## 6. Playlists `/playlists` ⬜ (app)
|
|
|
|
Listado de las playlists del usuario.
|
|
|
|
- **Grid** de playlists (portada, nombre, nº de tracks) → enlaza al detalle.
|
|
- **Crear playlist**: modal/página con nombre, descripción y portada
|
|
(`POST /playlists`, portada vía `POST /playlists/upload-picture`).
|
|
- **Estado vacío** con CTA.
|
|
- **Requiere sesión**.
|
|
|
|
## 7. Detalle de playlist `/playlists/[id]` ⬜ (app)
|
|
|
|
- **Cabecera**: portada grande, nombre, descripción, nº de tracks, botón «Reproducir todo».
|
|
- **Lista de tracks** (`GET /playlists/{id}/tracks`, paginada): índice, título, fecha,
|
|
play, quitar de la playlist (`DELETE /playlists/{id}/tracks/{trackId}`).
|
|
- **Acciones del dueño**: editar (`PUT`), borrar (`DELETE`) la playlist, reordenar (futuro).
|
|
- **Añadir tracks**: desde explorar/biblioteca (`POST /playlists/{id}/tracks/{trackId}`).
|
|
|
|
## 8. Perfil de usuario `/users/[id]` ⬜ (futuro)
|
|
|
|
Vista pública de un usuario: avatar, nombre, sus canciones y playlists públicas
|
|
(`GET /users/{id}`, `GET /tracks/users/{id}`, `GET /playlists/users/{id}`).
|
|
|
|
---
|
|
|
|
## Player global (PlayerBar) ✅
|
|
|
|
Barra fija inferior visible al reproducir. Info de la pista, transporte
|
|
(anterior/play-pausa/siguiente), barra de progreso y control de volumen. Encola listas
|
|
desde cualquier grid (`player.playQueue`). Reproduce DASH vía el proxy
|
|
`/api/tracks/:id/stream`, que pide manifiesto + ticket firmado al backend.
|
|
|
|
## Backend disponible (resumen)
|
|
|
|
| Recurso | Endpoints |
|
|
| --- | --- |
|
|
| Tracks | listar/buscar, detalle, por usuario, stream, crear, borrar, upload-urls |
|
|
| Playlists | CRUD, tracks de la playlist, add/remove track, upload-picture |
|
|
| Users | listar/buscar, detalle, crear |
|
|
|
|
Cliente tipado en `$lib/server/api.ts` (`openapi-fetch`, estilo ErrorOr). Consumir en
|
|
`load`/actions server, nunca desde cliente. Tipos en `src/lib/api/schema.d.ts`.
|