# Briefing para Claude Code — Fermenty · Paso 1: Clasificaciones

> Documento de traspaso. Contiene lo que **no** puedes descubrir leyendo el código:
> la intención de diseño, las decisiones ya tomadas y los límites de esta tarea.
> Todo lo que sí es descubrible (esquema, rutas, modelos) léelo tú directamente.
>
> Fecha: 2026-07-22 · Proyecto: Fermenty (ZYMOLAB SLU)

---

## 1. Qué se está construyendo

Fermenty es un SaaS de gestión y trazabilidad para fermentadores. Se está añadiendo su capacidad central: **un mentor que formula**. En vez de que el usuario siga una receta con cantidades fijas, dice qué sabor quiere y a qué temperatura fermenta, y un motor calcula las cantidades y predice las ventanas de tiempo.

La consecuencia estructural es que **las cantidades y los tiempos dejan de ser datos de catálogo y pasan a ser salida calculada**. Esa inversión es la que gobierna todos los cambios de esquema.

La cadena objetivo:

```
Clasificación → Guía → Receta → [MOTOR] → Tanda → Lote
   (navegación)  (marco)  (variación)      (hecho congelado)
```

- **Clasificación** — estantes de navegación y SEO. Hoy es una taxonomía microbiológica (láctica, acética…) y debe pasar a ser navegable.
- **Guía** — el marco de un fermento: pasos, papeles de ingrediente, coeficientes, barandillas.
- **Receta** — variación ligera sobre una guía. No posee pasos ni cantidades propias.
- **Tanda** — instancia real, con copia congelada de todo.

Si existe `docs/mentor.md` en el repo, léelo. Puede estar todavía en la v0.3; la vigente es la **v0.8**, y si la del repo es anterior, lo que dice este briefing manda.

---

## 2. Estado de los datos — léelo antes de tocar nada

**La aplicación no está en uso. No hay ni un solo usuario real.** Todo el contenido de la base es de prueba o creado por el propietario.

| Tabla | Filas aprox. | Nota |
|---|---|---|
| `users` | 9 | Todos de prueba |
| `batches` | 17 | Todas de prueba. **No hay histórico real** |
| `recipes` | 8 | Todas oficiales, `user_id` NULL |
| `fermentation_guides` | 12 | **Solo 5 tienen contenido real** |
| `ferment_types` | 21 | La mayoría son cáscaras vacías |
| `fermentation_categories` | 5 | Taxonomía microbiológica antigua |
| `newsletter_subscribers` | 204 | **Datos reales. No tocar** |
| `blog_posts` / `blog_post_views` | 15 / 272 | **Datos reales. No tocar** |

**Las cinco guías con contenido real son: Kombucha, Kéfir, Chucrut, Kimchi y Vinagre.** Todo lo demás en `ferment_types` y `fermentation_guides` es estructura vacía.

Consecuencia: **las migraciones pueden ser destructivas** en todo lo que no sea newsletter y blog. No hace falta backfill defensivo, ni columnas legacy, ni convivencia de modelos. Si algo se reemplaza, se borra.

---

## 3. Principios que gobiernan todos los cambios

Estos cinco no son estilo, son la corrección de errores concretos ya presentes en el esquema.

**1 · Un solo dueño por concepto.** Todos los bugs encontrados hasta ahora salen de propiedad duplicada: `guide_steps` y `recipe_steps` reclaman los mismos pasos, `batch_reviews` y `flavor_results` miden lo mismo, `batch_ingredients` apunta a dos orígenes a la vez, `quantity` vive en tres tablas, el tiempo está configurado en cuatro sitios. Antes de añadir algo, comprueba que nada más reclama ser dueño de eso.

**2 · Borrar, no deprecar.** Lo que se reemplaza se elimina en el mismo commit. Nada de «lo dejo por si acaso». Este proyecto ya tiene sedimento y el objetivo explícito del propietario es no acumular más.

**3 · Columnas donde el motor no llega, JSON donde sí.** Los coeficientes y parámetros del motor van a cambiar muchas veces. Si viven en columnas, cada cambio de opinión es una migración y acaba dejando columnas fósiles. Perfil objetivo, contexto y ficha del motor van como JSON; ingredientes, papeles, pasos, fechas, estados y trazabilidad van en columnas.

**4 · El tiempo es predicción, no configuración.** `default_duration_days`, `guide_steps.min_day/max_day`, `recipe_steps.min_day/max_day` y `batches.target_duration_days` son la misma idea equivocada repetida cuatro veces. Mueren, pero **no en este paso**.

**5 · El snapshot de la tanda es autónomo.** `batch_steps` y `batch_ingredients` ya guardan sus propios valores y eso está bien. Nunca hagas que una tanda dependa de leer una guía viva.

---

## 4. Lista de defunción

Once estructuras que deben desaparecer a lo largo del plan. Ninguna en este paso salvo las marcadas **[paso 1]**.

| # | Qué muere | Paso |
|---|---|---|
| 1 | `ferment_types.default_duration_days` | 3 |
| 2 | `guide_steps.min_day` / `max_day` como configuración | 2 |
| 3 | `recipe_steps.min_day` / `max_day` | 4 |
| 4 | `batches.target_duration_days` | 5 |
| 5 | `quantity` en `guide_ingredients` y `recipe_ingredients` | 2 y 4 |
| 6 | Propiedad de pasos en `recipe_steps` (title, description, actions) | 4 |
| 7 | Doble puntero `guide_ingredient_id`/`recipe_ingredient_id` en `batch_ingredients` | 5 |
| 8 | Doble FK de paso en `recipe_ingredients` | 4 |
| 9 | `batch_reviews` (absorbida por `flavor_results`) | 5 |
| 10 | `fermentation_guides.version` / `is_current` y el método `currentGuide()` | 2 |
| 11 | `FermentType` como capa de navegación | 3 |
| — | **Recetas publicadas que apuntan a guías sin contenido** | **[paso 1]** |
| — | **Tipos y guías cáscara sin contenido** | **[paso 1]** |

---

## 5. El plan completo (para que sepas dónde encaja esto)

1. **Clasificaciones** ← estás aquí
2. Guías y pasos
3. Fermentos (destino de `FermentType`)
4. Recetas
5. Tandas

Después: tabla maestra de ingredientes, ficha del motor, el motor, calibración, proveedores. Y al final del todo, aplanar las migraciones.

---

## 6. Tarea 0 — Inventario, sin escribir nada

Antes de cualquier cambio, entrega un informe. **No modifiques nada en esta tarea.**

1. Contenido actual de `fermentation_categories`: id, name, slug, position.
2. Los 21 `ferment_types` con: id, name, slug, categoría actual, número de guías, y si tienen recetas.
3. Las 12 `fermentation_guides` con: id, tipo, nombre, número de `guide_steps` y de `guide_ingredients`. **Esto identifica cuáles son cáscaras.**
4. Todos los puntos del código donde se navega por `FermentationCategory` o `FermentType`: rutas, controladores, vistas, componentes, seeders, comandos.
   - **Falsos positivos conocidos que NO hay que tocar:** `BlogCategory` y el enum `AbvCompliance`.
5. Código muerto que encuentres de paso: rutas sin vista, métodos sin llamadas, vistas sin ruta, comandos sin uso. Solo listarlo.

---

## 7. Tarea 1 — Los cambios

### 1.1 · Migración

Añadir `fermentation_category_id` a `fermentation_guides`: `bigint unsigned`, nullable, FK a `fermentation_categories` con `ON DELETE SET NULL`, con índice.

Este es el cambio que convierte la clasificación en la raíz real de la cadena. `ferment_types.fermentation_category_id` se queda por ahora — muere en el paso 3.

### 1.2 · Contenido de la taxonomía

Tres estantes:

| Nombre visible | Slug | Guías |
|---|---|---|
| Bebidas fermentadas | `bebidas-fermentadas` | Kombucha, Kéfir |
| Vegetales fermentados | `vegetales-fermentados` | Chucrut, Kimchi |
| Vinagres | `vinagres` | Vinagre |

No crees más estantes «para el futuro». La clasificación es contenido administrable y añadir uno luego es una fila.

**Mecánica:** `UPDATE` en sitio reutilizando los ids existentes donde el concepto mapee, `INSERT` los que falten, `DELETE` solo los que queden sin nadie apuntando. **No hagas DELETE + INSERT masivo**, dejarías `ferment_types.fermentation_category_id` en NULL.

Propón el mapeo viejo→nuevo tras la tarea 0 y espera confirmación antes de ejecutarlo.

### 1.3 · Backfill

Asignar `fermentation_category_id` a las cinco guías reales según la tabla anterior.

### 1.4 · Limpieza

- Las recetas publicadas que apuntan a guías sin contenido real (Cerveza de jengibre, Encurtidos en salmuera, Ginger Bug, y cualquier otra que salga del inventario) pasan a `status = 'draft'`. No las borres: son la receta por defecto de su guía y volverán cuando la guía exista.
- Los `ferment_types` y `fermentation_guides` cáscara: propón qué hacer con cada uno tras la tarea 0. Por defecto, `is_active = 0` en los tipos.

### 1.5 · Barrido de navegación

Que la navegación del catálogo pase por `Clasificación → Guía` en vez de `Clasificación → FermentType → Guía`. `FermentType` sigue existiendo y sus FKs siguen funcionando; solo deja de ser el camino.

---

## 8. Criterios de aceptación

- [ ] Las cinco guías reales tienen `fermentation_category_id`
- [ ] Existen exactamente tres clasificaciones, con sus slugs
- [ ] Ninguna receta con `status = 'published'` apunta a una guía sin `guide_steps`
- [ ] El catálogo navega clasificación → guía sin pasar por `FermentType`
- [ ] La app arranca, el catálogo se ve y se puede crear una tanda igual que antes
- [ ] `newsletter_subscribers`, `blog_posts` y `blog_post_views` intactos
- [ ] Ninguna columna, tabla o método añadido «por si acaso»

---

## 9. Fuera de alcance — no lo toques en este paso

- `FermentType` estructuralmente (paso 3). Sigue vivo y con sus FKs.
- `recipe_steps` y `recipe_ingredients` (paso 4).
- `batches` y todo lo que cuelga de ella (paso 5).
- `guide_steps.min_day/max_day` y las cantidades (paso 2).
- La tabla maestra de ingredientes, la ficha, el motor.
- Aplanar las migraciones. Va al final, cuando el esquema esté estable.

---

## 10. Cómo reportar

Tras la tarea 0, para antes de escribir. Entrega el inventario y el mapeo propuesto, y espera confirmación.

Tras la tarea 1: qué migraciones creaste, qué filas tocaste, qué archivos del barrido cambiaste, y **cualquier cosa que te obligara a desviarte de este briefing**. Si algo del briefing choca con lo que encuentras en el código, no lo resuelvas por tu cuenta: dilo.

### Dos preguntas para el propietario

1. **Cerveza de jengibre** — ¿es la versión con alcohol o la soda? Si lleva alcohol necesita su propio estante y serían cuatro, no tres.
2. **Slugs** — no hay tráfico en las URLs actuales, así que se pueden cambiar libremente. ¿Confirmas que no hay enlaces externos ni campañas apuntando a las rutas de categoría?
