feat: agregar checklist interactiva del TP

Co-authored-by: wsf <alejandro.sartorio@gmail.com>
Signed-off-by: wsf <alejandro.sartorio@gmail.com>
This commit is contained in:
wsf
2026-08-25 14:57:07 -03:00
parent d8815d1fc2
commit e04b30b33a
8 changed files with 44 additions and 3 deletions
+3
View File
@@ -64,6 +64,9 @@ sap_tfi_2026/
> **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)
> **Controlar la entrega con la checklist interactiva:**
> [https://cursos-uai.github.io/sap_tfi_2026/checklist.html](https://cursos-uai.github.io/sap_tfi_2026/checklist.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
+7
View File
@@ -54,6 +54,13 @@ 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.
## Checklist del Trabajo Práctico
Abrir `checklist.html` para controlar los diez grupos de entregables del TP:
requerimientos, casos de uso, dominio, prototipo, arquitectura, robustez,
secuencia, clases, patrones y testing estructural. Cada criterio admite una
evidencia y el progreso queda guardado localmente en el navegador.
## Alcance
Es un prototipo educativo, no una reproducción exacta ni conectada a Odoo. Los
File diff suppressed because one or more lines are too long
+10
View File
@@ -0,0 +1,10 @@
<!doctype html><html lang="es"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><meta name="description" content="Checklist interactiva para la entrega del Trabajo Práctico con ICONIX"><title>Checklist del TP · SAP-TFI-2026</title><link rel="stylesheet" href="styles.css"><link rel="stylesheet" href="checklist.css"></head>
<body class="checklist-body"><header class="topbar"><a class="brand" href="index.html"><span class="brand-mark">S</span><span><strong>SAP · TFI</strong><small>Laboratorio ICONIX</small></span></a><nav class="course lab-links"><a href="index.html">Prototipo</a><a href="ejercicios.html">Ejercicios</a><a href="guias.html">Guías</a><a class="active" href="checklist.html">Checklist</a></nav></header>
<main class="checklist-shell">
<section class="checklist-hero"><div><p class="eyebrow">Control de entrega</p><h1>¿Tu TP está completo y es trazable?</h1><p>Marcá cada criterio sólo cuando puedas señalar su evidencia. El progreso se guarda en este navegador.</p></div><div class="hero-score"><strong id="total-percent">0%</strong><span id="total-copy">0 de 0 criterios</span></div></section>
<section class="quality-gates" aria-label="Hitos de revisión"><article><span>1</span><div><b>RRR</b><small>Requerimientos</small></div></article><i>→</i><article><span>2</span><div><b>PDR</b><small>Diseño preliminar</small></div></article><i>→</i><article><span>3</span><div><b>CDR</b><small>Diseño crítico</small></div></article><i>→</i><article><span>4</span><div><b>V&amp;V</b><small>Testing y evidencias</small></div></article></section>
<section class="toolbar"><label class="search-box"><span>⌕</span><input id="search" type="search" placeholder="Buscar criterio o artefacto…"></label><div class="filters"><button class="active" data-filter="all">Todos</button><button data-filter="pending">Pendientes</button><button data-filter="done">Completos</button></div><button id="expand-all" class="quiet-button">Contraer todo</button><button id="reset-checklist" class="quiet-button danger">Reiniciar</button></section>
<div class="checklist-layout"><aside class="section-index"><p class="eyebrow">Entregables</p><nav id="section-index"></nav><div class="evidence-key"><b>Regla de oro</b><p>Un tilde sin archivo, página, diagrama, prueba o enlace verificable no cuenta como evidencia.</p></div></aside><section id="checklist-sections" class="checklist-sections" aria-live="polite"></section></div>
<section class="traceability-card"><div><p class="eyebrow">Chequeo transversal</p><h2>Cadena mínima de trazabilidad</h2><p>Elegí un caso de uso central y seguí la misma historia de extremo a extremo.</p></div><div class="trace-chain"><span>REQ</span><i>→</i><span>CU</span><i>→</i><span>UI</span><i>→</i><span>ROB</span><i>→</i><span>SEC</span><i>→</i><span>CLA</span><i>→</i><span>TEST</span></div></section>
<footer class="checklist-sources"><b>Fuentes:</b><a href="https://docs.google.com/document/d/1oThnR9euP2YW4K94A3oAoE3pvHdeDyNShRdwWDY-Nmk/edit?usp=sharing" target="_blank" rel="noreferrer">Temas técnicos ↗</a><a href="https://docs.google.com/document/d/1_ZjiF3pUANt0-bm4V6Xph6hdJuHCnxbp/edit?usp=sharing" target="_blank" rel="noreferrer">Apunte ICONIX ↗</a><a href="https://www.fceia.unr.edu.ar/ingsoft/testing-intro-a.pdf" target="_blank" rel="noreferrer">Testing ↗</a><a href="https://www.fceia.unr.edu.ar/ingsoft/testing-estruct-a.pdf" target="_blank" rel="noreferrer">Testing estructural ↗</a><a href="https://www.fceia.unr.edu.ar/ingsoft/p-testing.pdf" target="_blank" rel="noreferrer">Práctica ↗</a></footer>
</main><script src="checklist.js"></script></body></html>
+20
View File
@@ -0,0 +1,20 @@
const S=[
['req','Requerimientos','Capacidades y restricciones',[['Funcionales identificados, numerados y sin decisiones de implementación','Cada requisito expresa una capacidad observable.'],['No funcionales clasificados','Considerar seguridad, desempeño, usabilidad, portabilidad y disponibilidad.'],['Alcance, actores y glosario acordados','El vocabulario es consistente en todos los artefactos.'],['Cada requisito se vincula con casos de uso','La matriz permite recorrer REQ → CU.'],['Al menos un criterio de aceptación por requisito','Debe ser comprobable y describir el resultado esperado.']]],
['cu','Casos de uso y especificaciones','Comportamiento desde la mirada del actor',[['Diagrama general con actores, casos y límite del sistema','Cada actor persigue un objetivo claro.'],['include y extend usados con sentido','include es obligatorio reutilizado; extend, opcional o condicionado.'],['Una especificación por caso relevante','Incluye objetivo, actor, precondiciones, disparador y postcondiciones.'],['Curso básico escrito en voz activa','Cada paso muestra actor, acción y respuesta del sistema.'],['Alternativos, excepciones y reglas documentados','Cada desvío tiene condición, respuesta y cierre.'],['Hito RRR revisado con interesados','Casos de uso, dominio y prototipo capturan los requerimientos.']]],
['dom','Modelo de dominio','Vocabulario conceptual del problema',[['Clases tomadas del lenguaje del negocio','No incluye pantallas, controles ni detalles técnicos.'],['Atributos conceptuales relevantes','Evita claves foráneas y decisiones de persistencia.'],['Relaciones y multiplicidades justificadas','Cada asociación expresa un hecho del dominio.'],['Nombres sin sinónimos ni ambigüedades','El mismo concepto conserva su nombre.'],['Modelo actualizado después de robustez','Todas las entidades descubiertas aparecen en el dominio.']]],
['ui','Prototipo','Fronteras y recorrido del usuario',[['Pantallas y estados relevantes representados','Incluye formularios, listados, mensajes, confirmaciones y errores.'],['Cada pantalla se vincula con casos y actores','La navegación materializa cursos básicos y alternativos.'],['Controles y datos coinciden con las especificaciones','No hay acciones huérfanas ni entradas faltantes.'],['Prototipo revisado con usuarios','Se registraron observaciones y decisiones.'],['Se usa como especificación, no como producto final','Sirve para desambiguar y descubrir fronteras.']]],
['arch','Arquitectura','Estructura y decisiones técnicas',[['Vistas funcional, de datos y del sistema separadas','Cada una responde una pregunta arquitectónica.'],['Componentes, capas, responsabilidades e interfaces visibles','Las dependencias respetan el estilo declarado.'],['Despliegue, nodos y tecnologías documentados','Incluye persistencia e integraciones externas.'],['Decisiones justificadas por requerimientos','No se basan sólo en preferencias tecnológicas.'],['Calidad y testing considerados','Contempla cambio, seguridad, rendimiento y comprobabilidad.']]],
['rob','Diagramas de robustez','Puente entre casos de uso y diseño',[['Un diagrama por caso de uso diseñado','El texto se sigue frase por frase.'],['Actor, Boundary, Control y Entity diferenciados','Fronteras y entidades son sustantivos; controles, acciones.'],['Reglas de comunicación respetadas','Actor↔Boundary; Boundary↔Control; Entity↔Control.'],['Una frontera clara por pantalla o interfaz','Los nombres coinciden con prototipo y texto.'],['Entidades consistentes con el dominio','Toda entidad está en el modelo actualizado.'],['Controles cubren cursos básicos y alternativos','Sin asignar todavía métodos ni algoritmos.'],['Hito PDR aprobado','Texto, robustez, dominio, datos y arquitectura son consistentes.']]],
['seq','Diagramas de secuencia','Diseño detallado por escenario',[['Un diagrama por caso de uso','Incluye curso básico y alternativos.'],['Participantes derivados de robustez','No aparecen objetos sin responsabilidad explicada.'],['Texto del caso mapeado a mensajes','Orden, retornos, condiciones y ciclos son visibles.'],['Controles asignados a operaciones u objetos','Cada mensaje llega al responsable del comportamiento.'],['Mensajes respetan arquitectura y patrones','El detalle orienta la implementación.'],['Errores y resultados observables representados','Las respuestas regresan a la frontera.']]],
['class','Diagrama de clases','Modelo estático listo para implementar',[['Clases con responsabilidades, atributos y operaciones','Las operaciones surgen de secuencia.'],['Tipos, visibilidad y firmas especificados','Los contratos permiten comprender la colaboración.'],['Relaciones y multiplicidades correctas','Herencia y composición tienen necesidad demostrable.'],['Alta cohesión y bajo acoplamiento revisados','Cada clase protege un secreto coherente.'],['Interfaces aíslan decisiones que pueden cambiar','Se aplica ocultamiento de información.'],['Consistencia con dominio, secuencias y código','No faltan ni sobran elementos sin trazabilidad.'],['Hito CDR aprobado','Diseño completo, correcto, realizable y alineado.']]],
['patterns','Patrones de diseño','Problema, decisión y consecuencias',[['Cada patrón resuelve un problema concreto','Se explica contexto y necesidad.'],['Participantes y colaboraciones identificados','Las clases del TP se mapean a roles.'],['Clases reflejan la estructura del patrón','No es sólo un ejemplo genérico copiado.'],['Secuencias reflejan su comportamiento','Los mensajes muestran un escenario real.'],['Alternativas, beneficios y costos documentados','Evalúa acoplamiento, extensión y complejidad.']]],
['test','Testing estructural','Pruebas derivadas del código',[['Unidad, especificación y dominio de entrada definidos','Cada caso usa valores concretos y salida esperada.'],['Grafo de flujo de control construido','Nodos, decisiones y flechas corresponden al código.'],['Criterio de cobertura declarado','Distingue sentencias, ramas, condiciones y caminos.'],['Conjunto de pruebas satisface el criterio','Vincula entrada, camino, esperado y obtenido.'],['Cobertura medida y evidencia adjunta','Incluye reporte o cálculo verificable.'],['Casos normales, límites y fallas incluidos','La selección busca revelar defectos.'],['Pruebas re-ejecutables y resultado registrado','Documenta ambiente, versión, fecha y estado.'],['Trazabilidad hasta TEST comprobada','Una prueba demuestra cada requisito del alcance.']]]];
const K='sap-tfi-checklist-v1',root=document.querySelector('#checklist-sections'),index=document.querySelector('#section-index');let st=JSON.parse(localStorage.getItem(K)||'{}'),filter='all',query='';
const items=S.flatMap(([sid,,,a])=>a.map((x,i)=>[`${sid}-${i}`, ...x]));
const get=id=>st[id]||{done:false,evidence:''},esc=v=>(v||'').replace(/[&<>"']/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[c])),save=()=>localStorage.setItem(K,JSON.stringify(st));
function match(id,t,h){const x=get(id);return(filter==='all'||(filter==='done'?x.done:!x.done))&&`${t} ${h}`.toLowerCase().includes(query)}
function render(){root.innerHTML=S.map(([sid,title,sub,a],n)=>{const done=a.filter((_,i)=>get(`${sid}-${i}`).done).length,vis=a.map((x,i)=>[`${sid}-${i}`,...x]).filter(x=>match(...x));return`<article class="check-section open" id="section-${sid}" ${vis.length?'':'hidden'}><button class="section-head" aria-expanded="true"><span class="section-number">${String(n+1).padStart(2,'0')}</span><span><h2>${title}</h2><p>${sub}</p></span><span class="section-progress"><b>${done}/${a.length}</b><small>completos</small></span><span class="chevron">⌃</span></button><div class="section-body">${vis.map(row).join('')}</div></article>`}).join('');if(!root.querySelector('.check-section:not([hidden])'))root.innerHTML='<div class="empty-state">No hay criterios que coincidan con este filtro.</div>';index.innerHTML=S.map(([sid,t,,a])=>`<a href="#section-${sid}"><span>${t}</span><b class="count">${a.filter((_,i)=>get(`${sid}-${i}`).done).length}/${a.length}</b></a>`).join('');bind();total()}
function row([id,t,h]){const x=get(id);return`<div class="check-item ${x.done?'done':''}" data-id="${id}"><input id="${id}" type="checkbox" ${x.done?'checked':''}><div class="item-copy"><label for="${id}">${t}</label><p>${h}</p><input class="evidence-input" aria-label="Evidencia para ${t}" placeholder="Evidencia: archivo, página, URL, captura o reporte…" value="${esc(x.evidence)}"></div></div>`}
function bind(){document.querySelectorAll('.section-head').forEach(b=>b.onclick=()=>{const c=b.closest('.check-section');c.classList.toggle('open');b.setAttribute('aria-expanded',c.classList.contains('open'))});document.querySelectorAll('.check-item').forEach(r=>{const id=r.dataset.id,c=r.querySelector('[type=checkbox]'),e=r.querySelector('.evidence-input');c.onchange=()=>{st[id]={done:c.checked,evidence:e.value};save();render()};e.oninput=()=>{st[id]={done:c.checked,evidence:e.value};save()}})}
function total(){const done=items.filter(([id])=>get(id).done).length;document.querySelector('#total-percent').textContent=`${Math.round(done/items.length*100)}%`;document.querySelector('#total-copy').textContent=`${done} de ${items.length} criterios`}
document.querySelector('#search').oninput=e=>{query=e.target.value.trim().toLowerCase();render()};document.querySelectorAll('[data-filter]').forEach(b=>b.onclick=()=>{filter=b.dataset.filter;document.querySelectorAll('[data-filter]').forEach(x=>x.classList.toggle('active',x===b));render()});document.querySelector('#expand-all').onclick=e=>{const a=[...document.querySelectorAll('.check-section')],open=a.some(c=>!c.classList.contains('open'));a.forEach(c=>c.classList.toggle('open',open));e.target.textContent=open?'Contraer todo':'Expandir todo'};document.querySelector('#reset-checklist').onclick=()=>{if(confirm('¿Borrar todos los tildes y evidencias?')){st={};save();render()}};render();
+1 -1
View File
@@ -11,7 +11,7 @@
<body class="lab-body">
<header class="topbar">
<a class="brand" href="index.html"><span class="brand-mark">S</span><span><strong>SAP · TFI</strong><small>Laboratorio ICONIX</small></span></a>
<nav class="course lab-links"><a href="index.html">Prototipo</a><a class="active" href="ejercicios.html">Ejercicios</a><a href="guias.html">Guías</a></nav>
<nav class="course lab-links"><a href="index.html">Prototipo</a><a class="active" href="ejercicios.html">Ejercicios</a><a href="guias.html">Guías</a><a href="checklist.html">Checklist</a></nav>
</header>
<main class="lab-layout">
+1 -1
View File
@@ -11,7 +11,7 @@
<body class="guide-body">
<header class="topbar">
<a class="brand" href="index.html"><span class="brand-mark">S</span><span><strong>SAP · TFI</strong><small>Laboratorio ICONIX</small></span></a>
<nav class="course lab-links"><a href="index.html">Prototipo</a><a href="ejercicios.html">Ejercicios</a><a class="active" href="guias.html">Guías</a></nav>
<nav class="course lab-links"><a href="index.html">Prototipo</a><a href="ejercicios.html">Ejercicios</a><a class="active" href="guias.html">Guías</a><a href="checklist.html">Checklist</a></nav>
</header>
<main class="guide-shell">
+1 -1
View File
@@ -13,7 +13,7 @@
<span class="brand-mark">S</span>
<span><strong>SAP · TFI</strong><small>Laboratorio ICONIX</small></span>
</a>
<div class="course lab-links"><a class="active" href="index.html">Prototipo</a><a href="ejercicios.html">Ejercicios</a><a href="guias.html">Guías</a></div>
<div class="course lab-links"><a class="active" href="index.html">Prototipo</a><a href="ejercicios.html">Ejercicios</a><a href="guias.html">Guías</a><a href="checklist.html">Checklist</a></div>
</header>
<main class="workspace">