diff --git a/README.md b/README.md
index f196f83..6e51ec6 100644
--- a/README.md
+++ b/README.md
@@ -61,6 +61,9 @@ sap_tfi_2026/
> **Practicar con ejercicios interactivos:**
> [https://cursos-uai.github.io/sap_tfi_2026/ejercicios.html](https://cursos-uai.github.io/sap_tfi_2026/ejercicios.html)
+> **Resolver casos con hojas de ruta paso a paso:**
+> [https://cursos-uai.github.io/sap_tfi_2026/guias.html](https://cursos-uai.github.io/sap_tfi_2026/guias.html)
+
El directorio **`prototipo/`** contiene una representación interactiva de las
pantallas que actúan como fronteras (*boundaries*) en los diagramas de robustez.
Permite observar cómo los botones, formularios, tablas, mensajes y otros
diff --git a/prototipo/README.md b/prototipo/README.md
index b7f9aba..84d44bf 100644
--- a/prototipo/README.md
+++ b/prototipo/README.md
@@ -47,6 +47,13 @@ Los ejercicios ofrecen corrección inmediata, explicación de la respuesta y
progreso persistente en el navegador. La base teórica se encuentra citada al
pie de cada estación.
+## Guías paso a paso
+
+Abrir `guias.html` para resolver seis casos progresivos con una hoja de ruta:
+comprender el problema, anticipar cambios, descomponer, diseñar interfaces,
+establecer relaciones y validar el diseño. Cada paso permite registrar el
+razonamiento, solicitar una pista y comparar al final con una solución modelo.
+
## Alcance
Es un prototipo educativo, no una reproducción exacta ni conectada a Odoo. Los
diff --git a/prototipo/ejercicios.html b/prototipo/ejercicios.html
index 15432bb..246bb5a 100644
--- a/prototipo/ejercicios.html
+++ b/prototipo/ejercicios.html
@@ -11,7 +11,7 @@
No mires primero la respuesta. Registrá tus decisiones, pedí una pista cuando la necesites y compará tu propuesta recién al final.
+
0 / 6casos completados
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Método reutilizable para la práctica completa
+
La misma hoja de ruta sirve para los problemas no resueltos
+
1Separar hechos de decisiones2Anticipar cambios3Un secreto por módulo4Diseñar interfaces5Elegir relaciones6Documentar y someter a cambios
+
Aplicala a Celda de producción, Museo, Balanza de camiones, Procesamiento de imágenes, Estación climatológica, Exclusa y los demás enunciados de la práctica.
+
+
+
+
+
+
+
+
diff --git a/prototipo/guias.js b/prototipo/guias.js
new file mode 100644
index 0000000..39315e4
--- /dev/null
+++ b/prototipo/guias.js
@@ -0,0 +1,56 @@
+const cases=[
+ {id:"limite",short:"Límite",title:"Controlar extracciones",problem:"Una caja de ahorros ya permite depositar, extraer y consultar saldo. Se agrega la regla: no extraer más de $10.000.",steps:[
+ ["Separá lo estable de lo nuevo","¿Qué responsabilidad ya existe y cuál aparece con el nuevo requisito?","No confundas operaciones básicas de la cuenta con la política de límite."],
+ ["Detectá los ítems de cambio","¿Qué podría variar de forma independiente? Anotá al menos dos cambios futuros.","El monto puede cambiar, desaparecer o incorporar excepciones."],
+ ["Elegí los módulos","¿Qué secreto debería ocultar cada módulo?","Un módulo conserva la cuenta básica y otro la regla de extracción."],
+ ["Diseñá las interfaces","Escribí las operaciones públicas. ¿Conviene que ambos módulos presenten la misma interfaz?","Una interfaz compatible permite sustituir el objeto sin modificar clientes."],
+ ["Definí la relación","¿Quién usa o delega en quién? Representalo con una flecha.","El control envuelve o compone la cuenta y delega las operaciones permitidas."],
+ ["Someté el diseño a cambios","Probá cambiar $10.000 por un límite diario y luego eliminar la regla. ¿Qué módulos tocás?","El diseño es fuerte si CajaAhorros permanece intacta."]],solution:{idea:"Separar la política de la cuenta básica y usar delegación.",modules:[["CajaAhorros","Oculta representación y algoritmos del saldo."],["ControlExtraccion","Oculta la regla del límite y delega en CajaAhorros."]],relation:"ControlExtraccion ◇──▷ CajaAhorros; interfaces compatibles."}},
+ {id:"form",short:"Formulario",title:"Validar nombre y DNI",problem:"Un formulario recibe nombre y DNI. Al aceptar, el sistema verifica que el DNI exista y corresponda con el nombre usando una fuente de datos.",steps:[
+ ["Marcá las decisiones","¿Qué decisiones distintas hay en interfaz, regla y persistencia?","Pensá qué cambia si reemplazás GUI, regla o base relacional por separado."],
+ ["Listá cambios probables","Proponé una variación para cada decisión.","La presentación puede ser web; la regla puede pedir otro dato; la fuente puede ser una API."],
+ ["Asigná un secreto por módulo","Nombrá tres módulos y escribí el secreto de cada uno.","Frontera, regla de negocio y acceso a datos son tres motivos de cambio."],
+ ["Definí servicios abstractos","Diseñá interfaces sin SQL, widgets ni rutas de archivos.","La regla pregunta por una persona; no debería conocer SELECT ni tablas."],
+ ["Trazá la estructura de uso","Ordená: actor, formulario, control, repositorio.","La dependencia avanza desde la frontera hacia servicios abstractos."],
+ ["Revisá con ICONIX","Mapeá los módulos a Boundary, Control y Entity/Repository.","Formulario=Boundary; validación=Control; acceso a personas=servicio de datos."]],solution:{idea:"Aislar presentación, regla de validación y acceso a datos.",modules:[["FormNombreDNI","Oculta la implementación del formulario."],["ControlarNombreDNI","Oculta la regla de correspondencia."],["RepositorioPersonas","Oculta tecnología y esquema de persistencia."]],relation:"Form → Control → Repositorio; ninguna sentencia SQL en los dos primeros."}},
+ {id:"cuentas",short:"Cuentas",title:"Modelar tipos de cuenta",problem:"Caja de ahorro y cuenta corriente comparten operaciones, pero la primera no permite saldo negativo y la segunda sí.",steps:[
+ ["Compará comportamiento","Armá una tabla: qué operaciones comparten y cuáles cambian.","depositar y saldo son equivalentes; extraer tiene reglas distintas."],
+ ["Evitá banderas de tipo","Explicá el costo de una clase con tipo=CA/CC y condicionales.","Cada nuevo tipo agrega ramas y mezcla secretos."],
+ ["Separá implementaciones","Proponé una clase para cada variación de comportamiento.","Cada cuenta puede implementar extraer sin preguntar qué tipo es."],
+ ["Extraé una interfaz común","¿Qué abstracción permite tratar todas las cuentas de manera uniforme?","Una CuentaBancaria abstracta declara el contrato compartido."],
+ ["Elegí herencia con criterio","Dibujá generalización y justificá por qué es herencia de interfaz.","La sustitución sirve para clientes como calcularSaldoTotal."],
+ ["Probá extensión","Agregá una cuenta remunerada. ¿Cuántas clases existentes modificás?","El resultado deseable es agregar un heredero sin modificar los anteriores."]],solution:{idea:"Polimorfismo en lugar de una bandera de tipo y condicionales.",modules:[["CuentaBancaria","Interfaz abstracta común."],["CajaAhorros","Regla de extracción con saldo suficiente."],["CuentaCorriente","Permite saldo negativo."]],relation:"CajaAhorros y CuentaCorriente heredan la interfaz CuentaBancaria."}},
+ {id:"idioma",short:"Idioma",title:"Internacionalizar un formulario",problem:"El título y las etiquetas del formulario Nombre/DNI deben cambiar según el idioma configurado.",steps:[
+ ["Localizá los condicionales","¿Dónde aparecerían sentencias case si resolvieras todo dentro de dibujar()?","Habría ramas para título, etiquetas y botones."],
+ ["Separá motivos de cambio","¿Qué cambia por idioma y qué cambia por tecnología de interfaz?","Traducción y dibujo son decisiones independientes."],
+ ["Proponé una abstracción","¿Qué servicio puede pedir el formulario sin conocer un idioma concreto?","Puede solicitar textos mediante claves o una interfaz de recursos."],
+ ["Elegí implementaciones","Definí al menos dos implementaciones intercambiables.","RecursosES y RecursosEN implementan el mismo contrato."],
+ ["Usá composición","Mostrá cómo recibe el formulario su proveedor de textos.","El proveedor se inyecta al construir el formulario."],
+ ["Aplicá abierto/cerrado","Agregá portugués y contá qué cambia.","Se agrega una implementación y configuración; el formulario no cambia."]],solution:{idea:"Separar recursos lingüísticos de la implementación visual.",modules:[["RecursosFormulario","Interfaz de textos necesarios."],["RecursosES / RecursosEN","Implementaciones por idioma."],["FormNombreDNI","Dibuja usando un proveedor compuesto."]],relation:"FormNombreDNI ◇── RecursosFormulario; implementaciones sustituibles."}},
+ {id:"reuso",short:"Reuso",title:"Compartir implementación sin mezclar reglas",problem:"CajaAhorros y CuentaCorriente repiten el código de depositar y consultar saldo, pero difieren al extraer.",steps:[
+ ["Identificá repetición","¿Qué código es realmente común y qué parte expresa una regla variable?","La representación del saldo es común; la autorización de extracción difiere."],
+ ["Evaluá si es un ítem de cambio","¿La implementación común podría divergir entre tipos de cuenta?","Si puede divergir, heredar código crea acoplamiento evolutivo."],
+ ["Compará alternativas","Contrastá copiar, heredar implementación y componer un colaborador.","La composición permite delegar sin forzar una jerarquía de implementación."],
+ ["Diseñá el colaborador","Definí operaciones privadas de implementación del saldo.","Un objeto CuentaImp puede mantener y modificar el saldo."],
+ ["Dibujá ambas relaciones","Mostrá generalización de interfaz y composición de implementación.","Son relaciones con propósitos distintos."],
+ ["Documentá lo que UML no muestra","Escribí cómo delega cada operación y qué secreto queda oculto.","El diagrama solo no especifica interfaces, secretos ni delegación."]],solution:{idea:"Combinar herencia de interfaz con composición para compartir implementación.",modules:[["CuentaBancaria","Contrato común."],["CajaAhorros / CuentaCorriente","Reglas específicas."],["CuentaImp","Estado y operaciones básicas del saldo."]],relation:"Las cuentas heredan CuentaBancaria y cada instancia compone su propio CuentaImp."}},
+ {id:"secretos",short:"Secretos",title:"Un secreto por módulo",problem:"Un formulario localizado mezcla la forma de dibujarse con el idioma de sus textos. Debe poder cambiar cualquiera sin tocar la otra decisión.",steps:[
+ ["Enumerá secretos","¿Cuántas decisiones independientes oculta hoy el formulario?","Al menos dos: presentación y traducción."],
+ ["Refiná la granularidad","¿Conviene un módulo por título o un proveedor para todos los textos? Justificá.","La granularidad debe conservar cohesión sin crear interfaces inmanejables."],
+ ["Abstraé la interfaz","Escribí servicios que no revelen archivos, diccionarios ni variables de entorno.","titulo(), etiquetaNombre() o texto(clave) describen necesidades, no almacenamiento."],
+ ["Encapsulá implementaciones","Anotá qué detalles deben permanecer privados.","Codificación, archivo, locale y cache son internos al proveedor."],
+ ["Configurá en un punto estable","Decidí dónde seleccionar el idioma concreto.","La composición se realiza en el punto de arranque, no dentro del formulario."],
+ ["Cerrá con guía de módulos","Para cada módulo escribí Función, Secreto, Interfaz y Relaciones.","La figura UML comunica relaciones, pero no reemplaza esta documentación."]],solution:{idea:"La calidad surge de explicitar función, secreto, interfaz y delegación.",modules:[["FormNombreDNI","Oculta dibujo e interacción."],["TextosFormulario","Oculta selección y representación de textos."],["Configurador","Elige implementaciones al iniciar."]],relation:"Configurador crea Textos; Form lo recibe por composición y sólo conoce su interfaz."}}
+];
+
+const stepNames=["Comprender","Anticipar cambios","Descomponer","Diseñar interfaz","Relacionar","Validar"];
+let caseIndex=0,stepIndex=0;
+let state=JSON.parse(localStorage.getItem("iconix-guides")||"{}");
+function key(){return`${cases[caseIndex].id}-${stepIndex}`}
+function save(){localStorage.setItem("iconix-guides",JSON.stringify(state))}
+function caseDone(c){return c.steps.every((_,i)=>state[`${c.id}-${i}`]?.done)}
+function renderPicker(){document.querySelector("#case-picker").innerHTML=cases.map((c,i)=>``).join("");document.querySelector("#guide-completed").textContent=`${cases.filter(caseDone).length} / ${cases.length}`}
+function render(){const c=cases[caseIndex],s=c.steps[stepIndex],entry=state[key()]||{};document.querySelector("#case-label").textContent=`Caso ${caseIndex+1} · ${stepNames[stepIndex]}`;document.querySelector("#case-title").textContent=c.title;document.querySelector("#step-counter").textContent=`PASO ${stepIndex+1} DE 6`;document.querySelector("#problem-box").innerHTML=`Enunciado de trabajo ${c.problem}`;document.querySelector("#roadmap").innerHTML=c.steps.map((x,i)=>`