From 5f2b5bd5a237d94ecb1491bf20d99dfa1d81047e Mon Sep 17 00:00:00 2001 From: XShine555 Date: Tue, 22 Sep 2026 14:24:07 +0200 Subject: [PATCH] Translate CLAUDE.md to English and document new folder structure Fixes the stale /login reference (now /auth) and adds a Folder structure section covering lib/state, lib/data, lib/utils, components/layout and the ui/ category split from the recent reorganization. --- web-player/CLAUDE.md | 79 +++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 31 deletions(-) diff --git a/web-player/CLAUDE.md b/web-player/CLAUDE.md index 1d3c95b..831f86f 100644 --- a/web-player/CLAUDE.md +++ b/web-player/CLAUDE.md @@ -1,56 +1,73 @@ # Musify — web-player -Web pública de Musify (carpeta `web-player/`). Para diseño y recetas de UI usa el skill **`musify-web`**. +Musify's public web app (`web-player/` folder). For design and UI recipes, use the **`musify-web`** skill. ## Stack -SvelteKit 2 (`adapter-node`) · Svelte 5 **runes** · Tailwind 4 · TypeScript strict · auth OIDC Zitadel (`openid-client` + `jose`). +SvelteKit 2 (`adapter-node`) · Svelte 5 **runes** · Tailwind 4 · TypeScript strict · Zitadel OIDC auth (`openid-client` + `jose`). -No hay `svelte.config.js` (config inline en `vite.config.ts`) ni `tailwind.config.js` (config en `src/routes/layout.css`). +There is no `svelte.config.js` (config is inline in `vite.config.ts`) nor `tailwind.config.js` (config lives in `src/routes/layout.css`). -## Comandos +## Commands ```sh -npm run dev # servidor de desarrollo (puerto 5173) +npm run dev # dev server (port 5173) npm run build -npm run check # svelte-check — debe salir 0 errores antes de cerrar un cambio -npm run format # prettier --write . -npm run lint # prettier --check . && eslint . && npm run lint:tokens -npm run lint:tokens # scripts/check-tokens.mjs — guardrail del sistema de diseño (ver abajo) +npm run check # svelte-check — must exit 0 errors before closing a change +npm run format # prettier --write . +npm run lint # prettier --check . && eslint . && npm run lint:tokens +npm run lint:tokens # scripts/check-tokens.mjs — design-system guardrail (see below) ``` -## Reglas +## Rules -- **Sin comentarios** en el código salvo que sean imprescindibles. -- `npm run lint` y `npm run check` deben salir limpios antes de cerrar un cambio. -- **Svelte 5 runes siempre:** `$props()` con `interface Props`, `$state`, `$derived`, `$effect`. Nada de `export let` ni `$:`. `{#each}` siempre con clave. -- **Server-only bajo `$lib/server/`**; nunca importado desde cliente. -- Datos SSR vía `load` en `+page.server.ts`/`+layout.server.ts` → prop `data`. -- Enlaces a endpoints `+server.ts` (`/auth/login`, `/auth/logout`) llevan `data-sveltekit-reload`. -- Reutiliza los tokens/recetas del sistema de diseño; extrae a `$lib/components/ui/` lo que se repita. +- **No comments** in code unless essential. +- `npm run lint` and `npm run check` must exit clean before closing a change. +- **Always Svelte 5 runes:** `$props()` with `interface Props`, `$state`, `$derived`, `$effect`. No `export let` or `$:`. `{#each}` always keyed. +- **Server-only code under `$lib/server/`**; never imported from client code. +- SSR data via `load` in `+page.server.ts`/`+layout.server.ts` → `data` prop. +- Links to `+server.ts` endpoints (`/auth/login`, `/auth/logout`) carry `data-sveltekit-reload`. +- Reuse design-system tokens/recipes; extract to `$lib/components/ui/` whatever repeats. -## Estilos +## Folder structure -El sistema de diseño vive en `src/routes/layout.css` (tokens `@theme` + recetas `@utility`) y `src/lib/theme/` (`theme.css` para neutros estáticos, `tokens.ts` para los tokens dinámicos por hue de usuario). `scripts/check-tokens.mjs` (`npm run lint:tokens`, parte de `lint`) falla si `src/**/*.svelte` reintroduce lo que el refactor de `docs/frontend-refactor-plan.md` (P0–P14) eliminó — léelo antes de añadir un valor arbitrario o un radio/tamaño "de fábrica". +Full rationale and history in `docs/folder-structure-plan.md`. -- **Radios:** siempre `rounded-tag/thumb/control/art/art-lg/panel/panel-lg` (o `rounded-full` para píldoras/círculos). Nunca `rounded-sm/md/lg/xl/2xl/3xl` ni `rounded` a secas. -- **Tamaños cuadrados:** `size-*` en vez de `h-N w-N` repetido (icon: `size-icon-xs/sm/md/lg/xl`; portadas: `size-cover-xs…hero`). -- **Tipografía:** recetas `text-display-1/2/3/4`, `text-eyebrow`, `text-body`, `text-count`; tracking con `tracking-display`/`tracking-eyebrow`, no `tracking-[…]` suelto. -- **Espaciado:** escala de Tailwind en pasos de `.5` (evita cuartos como `.25`/`.75`; solo aceptables si el token semántico lo pide, p. ej. `mb-4.5` en `SectionHeading`). -- **Colores:** siempre `--mf-*`/`text-*`/`bg-*`/`border-*` de `theme.css`/`tokens.ts`. Nunca hex ni `rgba()` literales en un `.svelte` (esos literales solo existen como fuente de verdad dentro de `theme.css`/`tokens.ts`). -- **`style="…"` y arbitrarios `-[…]`:** solo la lista blanca de B.4 en `docs/frontend-refactor-plan.md` (stagger `--i`, hue de tile, posición de menú, anchos/alturas dinámicos vía `var(--mf-*)`, `text-[clamp(…)]`, `grid-cols-[auto_1fr]`, `max-h-[85dvh]`, paddings en `vh` para centrado vertical). Todo lo demás, a un token. -- Componentes base a reutilizar antes de crear uno nuevo: `Artwork`, `Avatar`, `ListRow`, `MediaIdentity`, `TrackList`, `MediaCard`, `PageHeader`, `ContextMenu`, `ConfirmDialog`, `PlayButton`, `Slider`, `Logo`, `Chip`, `SegmentedControl`, `CoverForm`. -- Gaps conocidos y aceptados (documentados en `scripts/check-tokens.mjs`): `strokeWidth={n}` en iconos no está unificado (13 valores distintos repartidos por casi todos los componentes; migrarlo a las recetas `stroke-thin/regular/bold` de forma segura requeriría poder verificar visualmente que `lucide-svelte` respeta `stroke-width` por CSS, así que se dejó fuera de esta pasada). +- `src/lib/state/` — reactive rune-based state (`*.svelte.ts` with no other home; player state stays in `$lib/player/`, theme mode in `$lib/theme/`). +- `src/lib/data/` — client-side domain/data helpers (albums, collections, genres, mixes, recentlyPlayed, search). +- `src/lib/utils/` — generic, domain-agnostic utilities (e.g. `format.ts`). +- `src/lib/components/layout/` — app chrome (Sidebar, TopBar, TabsBar, MobileHeader). +- `src/lib/components/player/` — player UI (PlayerBar, PlayerDock, Queue, TrackInfo, TransportControls). +- `src/lib/components/ui/` — design-system components, split by category: + - `primitives/` — generic controls with no music-domain knowledge (Button, Input, Chip, Slider, …). + - `overlay/` — anything that floats above content (Modal, ContextMenu, AccountMenu, …). + - `media/` — music-domain display components (Artwork, TrackList, MediaCard, PlayButton, …). + - `forms/` — composite entity forms (AlbumForm, PlaylistForm, CoverForm, ImageDropzone). + - `layout/` — page-level scaffolding (Page, PageHeader, SectionHeading) — distinct from `components/layout/`, which is the global app chrome. +- Auth routes live under `src/routes/auth/` (`+page.svelte` = login screen, `login/`, `logout/`, `callback/` = OIDC endpoints). Public user profile is `src/routes/(app)/user/[id]/`. + +## Styles + +The design system lives in `src/routes/layout.css` (`@theme` tokens + `@utility` recipes) and `src/lib/theme/` (`theme.css` for static neutrals, `tokens.ts` for user-hue-dependent dynamic tokens). `scripts/check-tokens.mjs` (`npm run lint:tokens`, part of `lint`) fails if `src/**/*.svelte` reintroduces what the `docs/frontend-refactor-plan.md` (P0–P14) refactor removed — read it before adding an arbitrary value or a "stock" radius/size. + +- **Radii:** always `rounded-tag/thumb/control/art/art-lg/panel/panel-lg` (or `rounded-full` for pills/circles). Never `rounded-sm/md/lg/xl/2xl/3xl` or bare `rounded`. +- **Square sizes:** `size-*` instead of repeated `h-N w-N` (icons: `size-icon-xs/sm/md/lg/xl`; covers: `size-cover-xs…hero`). +- **Typography:** recipes `text-display-1/2/3/4`, `text-eyebrow`, `text-body`, `text-count`; tracking via `tracking-display`/`tracking-eyebrow`, not a loose `tracking-[…]`. +- **Spacing:** Tailwind scale in `.5` steps (avoid quarters like `.25`/`.75`; only acceptable if the semantic token calls for it, e.g. `mb-4.5` in `SectionHeading`). +- **Colors:** always `--mf-*`/`text-*`/`bg-*`/`border-*` from `theme.css`/`tokens.ts`. Never literal hex or `rgba()` in a `.svelte` file (those literals only exist as the source of truth inside `theme.css`/`tokens.ts`). +- **`style="…"` and arbitrary `-[…]` values:** only the whitelist in section B.4 of `docs/frontend-refactor-plan.md` (stagger `--i`, tile hue, menu position, dynamic widths/heights via `var(--mf-*)`, `text-[clamp(…)]`, `grid-cols-[auto_1fr]`, `max-h-[85dvh]`, `vh` paddings for vertical centering). Everything else goes to a token. +- Base components to reuse before creating a new one: `Artwork`, `Avatar`, `ListRow`, `MediaIdentity`, `TrackList`, `MediaCard`, `PageHeader`, `ContextMenu`, `ConfirmDialog`, `PlayButton`, `Slider`, `Logo`, `Chip`, `SegmentedControl`, `CoverForm`. +- Known, accepted gaps (documented in `scripts/check-tokens.mjs`): `strokeWidth={n}` on icons isn't unified (13 distinct values spread across almost every component; safely migrating it to `stroke-thin/regular/bold` recipes would require visually verifying that `lucide-svelte` respects `stroke-width` via CSS, so it was left out of that pass). ## Auth -`hooks.server.ts` valida la cookie de sesión cifrada (`mf_session`), refresca el `access_token` y puebla `locals.user` / `locals.accessToken`. Para proteger una ruta, comprueba `locals.user` en su `load` y redirige a `/login?returnTo=…`. Para el backend, envía `locals.accessToken` como Bearer hacia `API_BASE_URL`. +`hooks.server.ts` validates the encrypted session cookie (`mf_session`), refreshes the `access_token`, and populates `locals.user` / `locals.accessToken`. To protect a route, check `locals.user` in its `load` and redirect to `/auth?returnTo=…`. For the backend, send `locals.accessToken` as a Bearer token to `API_BASE_URL`. -Variables de entorno en `.env` (ver `.env.example`): `ZITADEL_*`, `AUTH_REDIRECT_URI`, `AUTH_POST_LOGOUT_URI`, `SESSION_SECRET`, `API_BASE_URL`. +Environment variables in `.env` (see `.env.example`): `ZITADEL_*`, `AUTH_REDIRECT_URI`, `AUTH_POST_LOGOUT_URI`, `SESSION_SECRET`, `API_BASE_URL`. ## Backend API -Cliente tipado con `openapi-fetch` sobre el OpenAPI de `Musify.Api`. En un `load`/action server: +Typed client via `openapi-fetch` over `Musify.Api`'s OpenAPI spec. In a server `load`/action: ```ts import { createApiClient } from '$lib/server/api'; @@ -58,4 +75,4 @@ const api = createApiClient({ fetch, accessToken: locals.accessToken ?? undefine const { data, error: err } = await api.GET('/tracks'); ``` -Devuelve `{ data, error }` (estilo ErrorOr), no lanza. Los tipos viven en `src/lib/api/schema.d.ts` y se regeneran con `npm run gen:api` (requiere la API dev levantada en `API_BASE_URL`, que expone `/openapi/v1.json` solo en Development). +Returns `{ data, error }` (ErrorOr-style), never throws. Types live in `src/lib/api/schema.d.ts` and are regenerated with `npm run gen:api` (requires the dev API running at `API_BASE_URL`, which exposes `/openapi/v1.json` only in Development).