[CONSEJO — Doc 06] Contrarian: El mayor riesgo de UI para un producto técnico como StockMind es sobre-explicar el motor. Si el usuario tiene que leer para entender qué hace un número, ya perdiste. La regla es: si el insight no cabe en 6 palabras + 1 número, el diseño está mal. First Principles: El usuario objetivo es el dueño o gerente de una ferretería costarricense. Usa WhatsApp como app primaria, compra con transferencia SINPE, y aprende nuevos sistemas mirando a alguien usarlos. El diseño debe ser tan intuitivo como SINPE Móvil y tan rápido como WhatsApp. Expansionist: El sistema de diseño debe ser compartido con SalesMind, BookMind y PayMind. Construir componentes genéricos primero, variar el color de dominio por módulo. Una librería de componentes MindStack Suite reutilizable amortigua el costo de construir 4 frontends. Outsider: El mercado latinoamericano tiene conectividad variable. El frontend debe funcionar en 3G con timeout de 5 segundos en dispositivos de gama media. Si el dashboard tarda 8 segundos en cargar en un Moto G, perdiste al 40% de tu mercado objetivo. Executor: El MVP frontend tiene exactamente 3 pantallas críticas: dashboard de SKUs, detalle de SKU con forecast, y pantalla de OC sugerida. Todo lo demás es ruido hasta tener 10 clientes. Security Auditor: El frontend nunca expone datos de un tenant a otro. Los errores de React no pueden revelar datos del estado de otro usuario. Implementar error boundaries que limpien el state antes de mostrar pantallas de error. Chairman: La UI es la promesa visible del producto. Un motor estadístico perfecto con una UI torpe produce churn. La interfaz no es cosmética — es la mitad del valor del producto.
1. Stack tecnológico frontend
| Tecnología | Versión | Propósito |
|---|---|---|
| Next.js | 15 (App Router) | Framework principal, SSR/SSG, routing |
| React | 19 | UI library |
| TypeScript | 5.x | Type safety obligatorio |
| Tailwind CSS | 3.x | Utility-first styling |
| shadcn/ui | latest | Componentes base (Radix UI primitivos) |
| Recharts | 2.x | Gráficas de demanda, forecast, ABC |
| TanStack Query | 5.x | Data fetching, cache, sincronización |
| React Hook Form | 7.x | Formularios con validación |
| Zod | 3.x | Schema validation compartida con backend |
| next-intl | 3.x | i18n — español nativo, inglés fallback |
| Lucide Icons | latest | Set de iconos consistente |
CDN/Edge: Cloudflare CDN con edge caching de assets estáticos. Bundle size target: <200KB gzipped para ruta crítica.
2. Sistema de diseño
2.1 Paleta de colores StockMind
| Nombre | Hex | Uso |
|---|---|---|
| Teal principal | #00C2B8 |
CTA primario, elementos de acción, highlights |
| Teal oscuro | #009B92 |
Hover states, énfasis |
| Teal claro | #E6FAF9 |
Backgrounds activos, badges |
| Navy (Cheryx) | #0B1E3F |
Header, sidebar, texto primario sobre claro |
| Gris neutro | #F4F6F8 |
Background de página |
| Gris borde | #E2E8F0 |
Bordes, separadores |
| Gris texto | #64748B |
Labels, texto secundario |
| Verde éxito | #10B981 |
Stock OK, confirmaciones, NPS positivo |
| Amarillo alerta | #F59E0B |
Stock bajo, acción recomendada |
| Rojo crítico | #EF4444 |
Stockout, error, acción urgente |
| Gris inactivo | #94A3B8 |
Items deshabilitados, sin movimiento |
2.2 Tipografía
| Uso | Fuente | Peso | Tamaño |
|---|---|---|---|
| Headings | Inter | 700 (Bold) | H1: 24px / H2: 20px / H3: 16px |
| Body | Inter | 400 (Regular) | 14px base |
| Datos numéricos | Inter Tabular | 600 (SemiBold) | 14px–32px según contexto |
| Labels pequeños | Inter | 500 (Medium) | 12px |
| Código (API keys) | JetBrains Mono | 400 | 13px |
Nunca mezclar fuentes dentro de un componente. Inter Tabular para todos los números que el usuario compara visualmente (precios, cantidades, montos de OC).
2.3 Espaciado y layout
- Grid base: 8px
- Contenedor máximo: 1280px
- Sidebar: 240px fija en desktop, colapsable en tablet, drawer en mobile
- Content area: fluid, máximo 1040px
- Breakpoints: mobile <640px, tablet 640–1024px, desktop >1024px
2.4 Componentes de estado (iconografía semántica)
| Estado SKU | Color | Ícono | Significado |
|---|---|---|---|
| Stock crítico (stockout inminente) | Rojo #EF4444 |
AlertCircle |
OC urgente |
| Stock bajo (por debajo de punto de reorden) | Amarillo #F59E0B |
AlertTriangle |
OC recomendada |
| Stock OK | Verde #10B981 |
CheckCircle |
En rango óptimo |
| Sobrestock | Azul #3B82F6 |
TrendingDown |
Revisar next cycle |
| Sin datos suficientes (cold start) | Gris #94A3B8 |
HelpCircle |
Ingresa más historial |
3. Arquitectura de pantallas (MVP)
3.1 Mapa de navegación
/login — Magic link (no password)
/onboarding — Setup wizard (nuevo usuario)
/onboarding/empresa — Datos empresa
/onboarding/importar — Upload CSV / conectar Alegra
/onboarding/configurar — Parámetros iniciales (nivel servicio, lead time)
/dashboard — Vista principal (post-login)
/inventario — Lista de todos los SKUs
/inventario/[id] — Detalle de SKU + forecast
/ordenes — Órdenes de compra sugeridas + aprobadas
/ordenes/nueva — Crear OC manual
/ordenes/[id] — Detalle de OC + historial de aprobación
/proveedores — Gestión de proveedores
/reportes — Reportes de rendimiento (V1.1)
/configuracion — Cuenta + parámetros del motor
/configuracion/empresa
/configuracion/motor
/configuracion/integraciones
/configuracion/facturacion
/admin — Solo rol admin Cheryx (internal)
3.2 Pantalla: /dashboard
Propósito: dar una respuesta inmediata a "¿qué necesito hacer hoy?" sin que el usuario tenga que navegar.
Layout:
┌─────────────────────────────────────────────────────────┐
│ HEADER: Logo StockMind | Empresa | Notificaciones | Perfil│
├────────────────┬────────────────────────────────────────┤
│ │ ALERTAS PRIORITARIAS │
│ SIDEBAR │ ┌──────────────────────────────────┐ │
│ │ │ 3 SKUs en stockout crítico │ │
│ Dashboard │ │ → Ver órdenes urgentes │ │
│ Inventario │ └──────────────────────────────────┘ │
│ Órdenes │ │
│ Proveedores │ RESUMEN INVENTARIO │
│ Reportes │ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
│ Config │ │ 85 │ │ 23 │ │ 8 │ │ 12 │ │
│ │ │ OK │ │Bajo │ │Críti-│ │Sobre-│ │
│ │ │ │ │ │ │ co │ │stock │ │
│ │ └──────┘ └──────┘ └──────┘ └──────┘ │
│ │ │
│ │ PRÓXIMAS ÓRDENES DE COMPRA │
│ │ [tabla compacta: SKU · Cantidad · Prv] │
│ │ │
│ │ CLASIFICACIÓN ABC (pie chart mini) │
└────────────────┴────────────────────────────────────────┘
Principios de diseño del dashboard: - Las alertas siempre aparecen primero, antes de cualquier estadística - Los números grandes (85 OK, 23 Bajo) son clickables y navegan a la lista filtrada - Sin gráficas de línea en el dashboard principal (van en el detalle de SKU) - El "próximas OCs" muestra máximo 5 filas; más → link "Ver todas"
3.3 Pantalla: /inventario
Propósito: lista completa de SKUs con filtros y acceso rápido al detalle.
Componentes clave:
┌─── Filtros ────────────────────────────────────────────┐
│ [Buscar SKU...] [ABC: Todos▼] [Estado: Todos▼] [Exportar]│
└────────────────────────────────────────────────────────┘
┌─── Tabla de SKUs ──────────────────────────────────────┐
│ SKU | Descripción | ABC | Estado | Stock | Reorden | OC? │
│ ────┼─────────────┼─────┼────────┼───────┼─────────┼─────│
│ T-4 │ Tornillo 4" │ A │ ⚠️ Bajo│ 120 │ 200 │ → │
│ P-3 │ Pintura Blc │ B │ ✅ OK │ 45 │ 20 │ — │
│ ... │ ... │ ... │ ... │ ... │ ... │ ...│
└────────────────────────────────────────────────────────┘
Columnas requeridas (MVP): - SKU código + descripción (combinados, wrappable) - Clase ABC (badge de color: A=Teal, B=Gris, C=Claro) - Estado stock (badge con ícono semántico del sistema de colores) - Stock actual (número tabular) - Punto de reorden (número tabular, rojo si stock < punto) - Acción rápida (→ va al detalle / 🛒 crea OC directamente)
Comportamiento: - Ordenamiento por cualquier columna - Búsqueda fuzzy por SKU o descripción (debounce 300ms) - Filtro por clase ABC, por estado (crítico / bajo / ok / sobrestock) - Paginación server-side (50 items/página por defecto) - Virtualization si >500 SKUs visibles (react-virtuoso)
3.4 Pantalla: /inventario/[id]
Propósito: vista completa de un SKU con pronóstico, historia y gestión de OC.
Estructura de la pantalla:
┌─── Header SKU ─────────────────────────────────────────┐
│ T-4" Tornillo 4" pulgadas zincado │
│ Clase A · XYZ: Z (demanda errática) · Intermittent ✓ │
│ [Editar] [Crear OC] [Ver historial] │
└────────────────────────────────────────────────────────┘
┌─── Métricas rápidas ───────────────────────────────────┐
│ Stock actual Punto reorden OC pendiente Proveedor│
│ 120 200 — FERAX │
└────────────────────────────────────────────────────────┘
┌─── Gráfica de demanda + forecast ──────────────────────┐
│ [Recharts AreaChart] │
│ Historial 90d (gris) + Forecast 30d (teal) + CI 95% (sombreado)│
│ Marcas verticales: última OC recibida / próxima OC │
└────────────────────────────────────────────────────────┘
┌─── Explicación del motor (texto) ──────────────────────┐
│ "El motor seleccionó Croston TSB para este SKU porque │
│ su demanda es intermitente (ADI=2.4, CV²=0.38). El │
│ stock de seguridad es 45 unidades basado en un lead │
│ time de 14 días y variabilidad de demanda histórica." │
└────────────────────────────────────────────────────────┘
┌─── OC Sugerida ────────────────────────────────────────┐
│ Cantidad sugerida: 350 unidades │
│ Por qué: stock actual (120) llegará a punto de reorden │
│ (200) en ~8 días con lead time proveedor 14 días │
│ [✓ Aprobar y crear OC] [✗ Rechazar] [✎ Modificar cant.]│
└────────────────────────────────────────────────────────┘
┌─── Historial de transacciones ─────────────────────────┐
│ Fecha | Tipo | Cantidad | Notas │
│ Tabla collapsible, máximo 30 días visible por defecto │
└────────────────────────────────────────────────────────┘
El texto de explicación del motor es generado por el backend con Jinja2 templates en español. El frontend lo recibe como HTML sanitizado y lo renderiza — no usa LLM en runtime para esta explicación.
3.5 Pantalla: /ordenes
Propósito: gestión centralizada de todas las OCs en el sistema.
Tabs: - Pendientes (default): OCs sugeridas por el motor, esperando aprobación - Aprobadas: OCs aprobadas, no recibidas aún - Recibidas: OCs completadas (historial) - Rechazadas: OCs rechazadas (para análisis de motor)
Tabla de OCs pendientes:
| Col | Contenido |
|---|---|
| Prioridad | Ícono urgente/normal |
| SKU | Código + nombre |
| Proveedor | Nombre |
| Cantidad | Número tabular + unidad |
| Costo estimado | En USD o CRC según config |
| Fecha sugerida | "Ordenar antes del..." |
| Acción | [Aprobar] [Rechazar] [Modificar] |
Acciones en lote: seleccionar múltiples OCs + "Aprobar seleccionadas" para reducir fricción en días de compra.
3.6 Flujo de onboarding /onboarding
Wizard de 3 pasos (obligatorio para nuevos usuarios):
Paso 1 — Datos de empresa: - Nombre legal de la empresa - País (solo CR en MVP; campo deshabilitado para otros) - Sector (ferretería / distribuidora / importadora / farmacia / otro) - Nombre de la persona que usará el sistema (no el dueño necesariamente)
Paso 2 — Importar inventario: - Opción A: Upload CSV con template descargable - Opción B: Conectar Alegra (OAuth, disponible desde V1.0) - Opción C: Ingresar manual (solo si <50 SKUs; deshabilitado en Pro/Enterprise) - Validación en tiempo real del CSV: muestra errores de formato antes de subir
Paso 3 — Configurar parámetros iniciales: - Lead time promedio de proveedores (días) - Nivel de servicio deseado (slider: 90% / 95% / 97.5% — nombres descriptivos, no estadística) - Moneda de trabajo (CRC / USD) - Fecha de inicio del inventario (para cold start)
Al completar → el motor empieza a procesar. Pantalla de "procesando" con progress indicator y mensaje: "Analizando [X] SKUs... El análisis completo puede tomar hasta [Y] minutos."
4. Componentes reutilizables críticos
4.1 <SkuStatusBadge />
Props: status: 'critical' | 'low' | 'ok' | 'overstock' | 'nodata'
Renderiza: badge con color semántico + ícono + label en español. No texto en inglés visible al usuario.
4.2 <ForecastChart />
Props: history: TimeSeriesPoint[], forecast: ForecastPoint[], ci: ConfidenceInterval[]
Recharts AreaChart con tooltip personalizado que muestra fecha + valor + intervalo de confianza.
- Eje X: fechas en formato DD MMM (ej: "15 May")
- Eje Y: unidades (nunca porcentajes en este contexto)
- Hover: tooltip bilingüe, valores con separador de miles en español (. para miles, , para decimales)
4.3 <OrderCard />
Tarjeta compacta para OC sugerida. Contiene: SKU, cantidad, proveedor, justificación en texto, botones de acción. Usado tanto en /dashboard como en /ordenes y /inventario/[id].
4.4 <MotorExplanation />
Renderiza HTML sanitizado del texto generado por el backend (Jinja2). Estilo tipográfico consistente. No permite HTML arbitrario — solo tags seguros: <p>, <strong>, <em>, <ul>, <li>.
4.5 <DataTable />
Tabla genérica con: ordenamiento, búsqueda, paginación, selección múltiple, exportación CSV. Construida sobre TanStack Table. Acepta columnas tipadas con TypeScript.
4.6 <EmptyState />
Estado vacío estandarizado: ilustración SVG simple + mensaje contextual + CTA. Ejemplo: "No hay SKUs críticos — su inventario está saludable" con ícono verde.
5. Autenticación y roles (UI)
5.1 Magic link (sin contraseña)
Flujo de login:
1. Usuario ingresa email en /login
2. Backend envía magic link vía Resend (validad 15 min, un solo uso)
3. Click en link → verificación server-side → session JWT creada → redirect a /dashboard
4. Session dura 30 días (renovación automática si activo)
No hay pantalla de "crear contraseña". No hay "forgot password". El magic link es el mecanismo.
5.2 Roles y permisos (UI visible)
| Rol | Acceso UI |
|---|---|
| Owner (dueño) | Todo. Puede ver facturación, cambiar configuración del motor, invitar usuarios |
| Manager (gerente) | Dashboard + inventario + OCs + proveedores + reportes. No facturación |
| Viewer (solo lectura) | Dashboard + inventario (no puede crear OCs). Sin configuración |
| Cheryx Admin | Acceso /admin — internal only, invisible para tenants |
Los elementos UI para los que el usuario no tiene permiso están ocultos (no deshabilitados), para no confundir con funcionalidad pagada.
6. Rendimiento y accesibilidad
6.1 Objetivos de rendimiento
| Métrica | Target |
|---|---|
| LCP (Largest Contentful Paint) | <2.5s en 4G |
| FID / INP | <100ms |
| CLS | <0.1 |
| Bundle inicial (gzipped) | <200KB |
| Tiempo hasta primera OC visible | <3s en conexión 4G |
| Timeout API calls | 8s (muestra skeleton, no spinner infinito) |
Estrategias: - Next.js App Router con RSC para reducir bundle cliente - Lazy loading de gráficas (Recharts solo se carga al entrar al detalle de SKU) - TanStack Query con stale-while-revalidate: datos inmediatos del cache, refresco en background - Paginación server-side: nunca cargar todos los SKUs al cliente - Images: next/image con lazy loading y blur placeholder
6.2 Accesibilidad (WCAG 2.1 AA mínimo)
- Todos los inputs tienen
labelasociado (no solo placeholder) - Contraste mínimo 4.5:1 para texto sobre fondos (verificado con herramienta automática)
- Navegación por teclado: todos los elementos interactivos son focusables con Tab
- ARIA labels en iconos sin texto (ej: botón de aprobar OC con solo ícono)
- El estado de las alertas (crítico, bajo, ok) no depende solo del color — siempre acompañado de texto o ícono
- Screen reader: tablas con
<caption>y headersscope="col"correctos
7. Internacionalización (i18n)
- Idioma base: Español (Costa Rica) —
es-CR - Idioma fallback: Inglés —
en - Fechas: formato DD/MM/YYYY (CR estándar)
- Moneda CRC: símbolo ₡, separador miles con punto (₡1.250.000), decimales con coma
- Moneda USD: símbolo $, separador miles con coma ($1,250.00)
- Números estadísticos (CV, ADI): siempre con punto decimal, nunca coma (convención internacional)
- Días de la semana: lunes = primer día de la semana (CR estándar)
next-intl gestiona todos los strings de UI. Ningún string hardcodeado en componentes — todo pasa por t('key').
8. Estados de error y vacios
| Situación | UI |
|---|---|
| API error 500 | Toast "Algo salió mal. Intenta de nuevo." + opción de reportar |
| API timeout (>8s) | Skeleton desaparece + "La carga está tardando más de lo usual. [Reintentar]" |
| Sin SKUs importados | EmptyState con CTA "Importar inventario" |
| SKU sin historial suficiente | Badge "Sin datos suficientes" + tooltip explicando cuántos días se necesitan |
| Sesión expirada | Redirect a /login con mensaje "Tu sesión expiró. Ingresa tu email para continuar." |
| Error de red | Toast con ícono WiFi tachado + "Sin conexión. Los cambios se guardarán cuando vuelvas." |
9. Pantallas fuera de scope MVP (V1.1+)
Las siguientes pantallas no se construyen en MVP (meses 1–3):
- /reportes completo — solo mockup estático en MVP
- /proveedores con historial de precios — CRUD básico en MVP, historial en V1.1
- Dashboard mobile nativo — responsive web en MVP, app nativa en V2.0
- Multi-empresa — una empresa por cuenta en MVP
- Portal del proveedor (supplier self-service) — V1.1
Ver también: Doc 07 (SRD Backend — contratos de API que consume este frontend) · Doc 09 (Motor Core — explicaciones del motor que el frontend renderiza) · Doc 11 (Branding — paleta completa, logo, voz de marca) · wiki/04-stack-tecnico.md (decisiones de stack confirmadas)