# F-100 — Generación automática de SKU desde el título ## Backend - `src/modules/catalog/domain/sku.ts` (helper puro): - `generateSkuFromTitle(title)`: normaliza mayúsculas, diacríticos, separadores; produce `MV-` (max 100 chars). - `uniqueSku(base, existing)`: añade `-2`, `-3`, … hasta encontrar uno libre; truncando a 100 chars. - `src/modules/catalog/tests/sku.test.ts` (9 tests): normalización, acentos, `&`, hyphens, longitud, mayúsculas, lowercase collisions, truncado. - `src/modules/catalog/domain/ports.ts` + `pg-variant-repository.ts`: nuevo `listAllSkus()` para reutilizar en la creación. - `src/modules/catalog/api/catalog.routes.ts`: - `POST /products/sku:generate` (admin): recibe `{ title }` y devuelve `{ sku }` único. - `POST /products`: la variante por defecto ahora se crea con `generateSkuFromTitle(product.name)` + `uniqueSku` en vez de `SKU-MV-${uuid}`. - `GET /products/:id/variants` (lazy migration): igualmente usa SKU derivado del título. ## Admin UI (apps/admin) - `lib/api-client.ts`: `productsApi.generateSku(title)`. - `features/products/components/sections/PriceStockSection.tsx`: - Nuevo bloque "SKU" con input editable (validación `^[A-Za-z0-9-]+$`), botón `↻` para regenerar sugerencia. - Guardado en blur/Enter; mensajes: `✓` / `SKU duplicado` / `SKU inválido`. ## Evidencia - `npm run typecheck` (backend) OK. - `npm test`: 169 passed / 0 failed (9 nuevos). - `apps/admin tsc --noEmit` OK. - Smoke: `POST /products/sku:generate { "title": "Aceite de Oliva Virgen Extra" }` → `{ "sku": "MV-ACEITE-DE-OLIVA-VIRGEN-EXTRA" }`.