# Revisión de usabilidad — julio 2026

Revisión de UX del sitio público (fermenty.es) y de la app (app.fermenty.es)
a partir de: (a) revisión de código propia, (b) hallazgos de Manu, y (c) un
informe heurístico externo hecho en vivo sobre producción (31-07-2026).
Todo lo de abajo quedó **aplicado** en esta tanda salvo la sección «Pendiente».

## Arranque de la PWA

- `public/app.webmanifest` (solo la superficie móvil, vía
  `layouts/favicon` parametrizado): `start_url: /home` — la app instalada abre
  en Inicio, no en la bienvenida. El sitio público conserva `site.webmanifest`.
- La bienvenida es de un solo uso: redirige a Inicio si hay token **o**
  `fm_onboarded` (antes: solo standalone+token). «Explorar la app» y el
  «Saltar» del tour marcan `fm_onboarded`.
- CTAs de bienvenida: 1 primaria («Explorar la app») + 1 secundaria («Ya tengo
  cuenta») + tour como enlace discreto. Antes había 4-5 en competencia.
- Splash: mínimo artificial 2000 ms → 600 ms.

## Crear lote / asistente

- El nombre del lote es **opcional** en web y API: la sugerencia («Mi X») viaja
  como `placeholder` y el servidor la aplica si llega vacío. Nunca un valor
  precargado que haya que borrar. (`BatchController@store` web + API v1.)
- Renombrado inline del asistente: `focus()` + `select()` reales (el x-ref vive
  en un template x-if; hace falta el setTimeout + fallback por id).
- `.fm-chip` **existía solo como clase huérfana** — los botones del formulador
  («¿Dónde va a fermentar?», «Hoy/Otro día») salían como botones nativos sin
  estilar. Definida en `_app.scss` con min-height 44px.
- `.fm-btn:disabled` no tenía estilo: «Ver la fórmula» parecía pulsable estando
  deshabilitado. Ahora opacity .5 + cursor.

## AUTH (prioridad de Manu)

- **Reset de contraseña desde la app**: `POST /v1/forgot-password` (broker +
  Mailable de marca ya existentes; respuesta neutra, throttle 5/10min),
  pantalla `/recuperar` y enlaces en login + hoja global. El formulario web de
  reset (donde aterriza el correo) se rehízo al estilo Fermenty, en español.
- **Google en la app**: la app manda a `fermenty.es/auth/google?superficie=app`
  (misma redirect URI de la consola de Google — sin cambios allí); el callback,
  al ver la marca en sesión, crea un código de un solo uso (cache, 60 s) y
  rebota a `app.*/auth/google/volver#code=…`; la vista puente lo canjea en
  `POST /v1/google-exchange` por un token Sanctum. Botón «Continuar con
  Google» en login, registro y hoja (partial `_google-btn`, conserva `next`).
- Confirmación de contraseña eliminada (registro web + reset): un solo campo
  con «mostrar contraseña» (toggle también en las pantallas de la app).

## Accesibilidad móvil

- Viewport de la app sin `maximum-scale/user-scalable` (WCAG 1.4.4); el
  auto-zoom de iOS se evita con inputs a **16px** (`.fm-input`, `.fm-field`).
- Targets del topbar a 44px (atrás, campana, perfil — el círculo visible del
  avatar se queda en 34 dentro de un área de 44).
- `inputmode` en los numéricos del wizard web de lote.

## App — navegación y coherencia

- **Estadísticas del perfil navegables** (petición de Manu): Total/Activos/
  Completados → Fermentos `#lotes`/`#lotes-activos`/`#lotes-completados`
  (hash nuevo que pre-selecciona la píldora); Posts → tu página de comunidad.
  «Recetas propias» sin destino propio aún → sin enlace.
- Nomenclatura **Pro** en todas partes: badge del perfil («Plan Pro/Gratis»),
  banner («Pásate a Pro»), pantalla /premium (título, copy y CTA — ya no
  promete «7 días gratis», que no existe en billing), badges del Lab, sorteo
  del banner de instalación.
- **Ruta puente `/suscripcion` en la app** → redirect al panel web: el «Pasar a
  Pro» del sitio público en superficie móvil aterrizaba en un **404**.
- Banner de instalación: cierre persistente (7 días de descanso, máx. 3
  cierres) — ocupaba media pantalla de Inicio en cada visita.
- Avisos del Plan con el **nombre del lote** (dos kefires = dos avisos iguales
  sin saber cuál era cuál; el API ya mandaba `batch.name`).
- Pantalla «Planificador» → «Plan» (igual que su pestaña).
- Chips de comunidad sin scrollbar visible en escritorio.
- Errata: «Esta la formula el mentor» → «Esta receta la formula el mentor».

## Sitio público / legales

- Bug de plantilla: `@yield` dentro del atributo de `<x-seo>` en
  `legal/layout` salía **literal** en el `<title>` de las 4 legales — ahora se
  captura con `yieldContent` y se pasa como atributo dinámico.
- **Condiciones reescritas al producto real** (plataforma de fermentación
  casera, plan gratuito + Pro por Stripe en la web, PWA sin tiendas, carácter
  orientativo de las guías, soporte vía contacto). El aviso legal y la política
  de privacidad pierden las menciones a «SaaS para productores», APPCC y
  Google Play/App Store. `config/legal.php sites`: `erp` → `app`
  (app.fermenty.es). Huérfanas `pages/terminos` y `pages/privacidad` borradas.
- Enlace del registro directo a `/condiciones` (el alias `/terminos` queda para
  enlaces históricos).
- Branding: sufijo de título «Fermenty» (no «Fermenty.app») en layouts
  auth/guest/admin y ~15 vistas; footer, correos y newsletter igual.
- Calculadora de salmuera pública: sin peso precargado; sin cantidad muestra
  la **proporción** (%) e invita a escribir el peso para dar gramos. La de la
  app igual (water vacío + placeholder).

## Precios Pro — decidido (2026-07-31)

El precio publicado (4,99 / 12,99 / 39, el que Stripe cobra de verdad) **ES la
tarifa Early Bird**: no existe una segunda lista de 3,49/29 (esa banda
anunciaba importes que el checkout nunca cobraba). El copy en home, página Pro
y checkout del panel lo encuadra así: «el precio de hoy se te queda para
siempre; cuando la app avance, subirá». Los precios `earlybird_*` de
`config/billing.php` quedan sin uso de cara al público. La home añade la línea
Early Bird bajo la tarjeta Pro (`planes.pro_early`, es/en/de). El enlace del
footer público pasa de «Versión móvil» a **«Abrir la app»**.

Deuda menor que sigue: `pro.blade.php` hardcodea los importes que
`config/billing.php` promete centralizar.

## Ronda 3 (2026-07-31, tarde): el tiempo real del lote

Todos los síntomas que reportó Manu (aviso del kefir 12 h antes, 40% recién
montado, «listo para colar» tras completar un paso adelantado) compartían raíz:
el modelo pensaba en días-calendario y en pasos, no en horas.

- **Progreso**: el API devolvía pasos hechos/total (montar la receta = 40%);
  ahora usa el mismo cálculo horario que la web (`overallProgressPercentage`),
  con **+1%** por paso (antes 2) y la duración REAL de la tanda
  (`expected_end_date`, que recoge ajustes y motor) en vez del default de la
  guía.
- **Avisos por día** anclados a `fermentationStartedAt()` (hora real de
  arranque), no a la medianoche de `start_date`: kefir montado a las 18:00 →
  aviso a las 18:00 del día siguiente. El cron de correos ya corría cada 15
  min, así que la precisión llega al email.
- **Avisos de paso**: completar un paso antes de tiempo activa el siguiente,
  pero su aviso se agenda para `min_day` del paso (no `now()`).
- **`alertWindow`** deja de asomar lo de los 2 días siguientes: un aviso es
  aviso cuando TOCA; lo que viene lo cuenta la cronología del Plan.
- **Cata**: no se propone hasta el 50% de progreso (recién montada no hay nada
  que catar).
- **Bitácora**: el acceso solo aparece cuando hay registros (antes llevaba a
  una pantalla vacía).
- Chip **«Medida» → «Azúcar» (°Bx)** (decisión posterior el mismo día): en
  obrador pequeño se mide Brix, no acidez titulable. El API acepta ahora
  `ph|temperature|brix|salinity|note` (igual que la web); la **acidez sale del
  registro rápido** y volverá como herramienta Pro/Scale. Las mediciones de
  acidez ya guardadas se siguen leyendo en la bitácora.
- **ABV estimado**: con un °Bx inicial y otro final (azúcar consumido → alcohol,
  misma fórmula que la calculadora del Lab, `AbvCalculator::fromBrix`), el
  resource expone `abv_estimate` y se enseña en la bitácora de la app y en los
  «Datos del lote» de la crónica web. Null si no hay dos lecturas o el azúcar
  no bajó.

## Pendiente (decisiones de producto)
- **Flujo «Nuevo lote» con paso muerto** (informe #7): con recetas de motor,
  la pantalla intermedia solo elige receta y cede al formulador. Propuesta:
  «+ Nuevo» → selector de receta del formulador directamente.
- **Formular sin cuenta** (informe #19): el afinador público calcula sin
  registro; el formulador de la app exige cuenta antes de calcular. Propuesta:
  permitir formular en modo exploración y pedir cuenta al guardar/arrancar.
- No reproducibles en el código actual (¿deploy anterior?): hreflang `de_DE`
  en el afinador (DE está `activo => false`), «carrusel» del Lab (es lista
  vertical <600px), «Miel (hace Jun)» (no aparece; probablemente dato).
- El informe externo creó un **lote de prueba real** en la cuenta de Manu
  («Guía clásica de Kombucha», nº 29) — borrarlo desde la app cuando quiera.
