# 🧩 HANDOFF — Odoo-INT (Asus) → copia `odoo` en la ws

**De:** agente `odoo-int` (Asus) · **Para:** agente `odoo` (ws, gateway Rocky WS)
**Fecha:** 2026-11-04 · **Propósito:** dejarte TODO lo que tengo — contexto, reglas, inventario del contenido y el SPEC de Javi — para que sigas el pipeline en la ws sin perder nada.

> Cómo usarlo: léelo completo, intégralo a tus `AGENTS.md` / `TOOLS.md` / `MEMORY.md` / `memory/`, y ejecuta lo que marque como PENDIENTE. Al final está el "cómo continuar".

---

## 1. Identidad y misión (resumen)

- **Rol:** dueño de la operación de Odoo 18 en producción y de las **adaptaciones INT** sobre el ERP.
- **NO soy "el agente de eLearning"**: eLearning/HUB es UNA responsabilidad, no mi identidad.
- **Misión:** que Odoo sea la plataforma operativa de INT (no un LMS pegado). Adaptaciones: recursos, especialidades/rutas (A–F), certificaciones, recordatorios multicanal, chatter. Todo empaquetado como módulo `int_*` reutilizable.
- **Vibe:** ingeniero de ERP metódico. Sin snapshot no hay cirugía. Nada de "ya quedó" sin E2E real.
- **Reporto a Javi.** Coordino con Rocky WS (`main`), que orquesta la flota.

## 2. Regla de hardware y modelos — INNEGOCIABLE (Javi)

- **Imágenes SIEMPRE locales en la ws** (2× RTX 5090) con **ComfyUI + Qwen-Image 2.1 (open source)**, puertos **8198 (GPU0)** y **8199 (GPU1)**.
- **PROHIBIDO** cualquier modelo de imagen de pago (gemini-*-image, gpt-image-*, fal, etc.) salvo aprobación explícita de Javi.
- **Texto:** DeepSeek API OK (barato). 100% local → `ollama/qwen3-coder:30b` / `gpt-oss:20b`.
- Antes de gastar un centavo en un modelo comercial → parar y preguntar a Javi.

## 3. Invariantes técnicos (lecciones ya pagadas)

- `arch_db` por ORM **no** invalida cache QWeb → `docker restart odoo` (y en temas: borrar `ir.attachment` de `/web/assets/%` + restart).
- `slide.is_preview` viene `False` → `invite_error=no_rights`; poner `True` al crear.
- `survey.question.create` por XML-RPC falla → usar `docker exec -i odoo odoo shell`.
- `slide.channel.tag` exige `group_id` (grupo "Ruta" = 4).
- Nginx del HUB devuelve **403 a HEAD con UA python** → validar con `curl` GET.
- Vistas heredadas: revisar envoltorio `<data inherit_id=...>` (462 vistas con patrón roto en BD).
- Backups de archivos editados: `.bak`/`_vN` siempre; nunca SCP directo a prod sin copia previa.
- **Odoo 8069 cerrado a Internet** → túnel `ssh -N -L 8069:127.0.0.1:8069 linode-intt`.
- **jsonb traducible** (Odoo 18): `slide_channel.name` y `slide.slide.html_content` son `{"en_US": ...}`. SQL: `name->>'en_US'` / `html_content::text`. ORM XML-RPC acepta string plano. `website_url` es calculado.
- En esta BD el manifest `assets` NO crea `ir.asset` → usar `ir.asset` explícito (o `-u int_theme`).
- `gen_lesson_art_qwen.py` YA tiene variantes LIGHT/DARK (campo `variant`).

## 4. INVENTARIO del contenido (Odoo producción, 2026-11-04)

**Totales:** 65 cursos (`slide.channel`) · 770 slides (708 article + 58 certification + 3 document + 1 infographic) · 6 rutas (A–F) + 22 cursos de inducción/catálogo sin ruta.

**Leyenda de estatus de imágenes (verificadas contra archivos reales en `/opt/ia-intt/html/ruta-*/img`):**
- ✅ **Completa** — imágenes de ruta generadas y publicadas (existen los bloques hero, s1..s4).
- 🟠 **Parcial** — referencia imágenes de ruta pero FALTAN archivos en el servidor (no publicadas / generadas a medias).
- 🟡 **HUB-legacy** — aún apunta a `assets/lessons/` del HUB viejo (no migrada al pipeline de rutas).
- 🔴 **Sin imagen** — article sin referencia a imagen.
- ⬜ **N/A** — certificación/documento (no lleva imagen de lección).

### 4.1 Resumen por ruta

| Ruta | Cursos | Artículos | ✅ Completa | 🟠 Parcial | 🟡 HUB-legacy | 🔴 Sin img | ⬜ Cert/doc |
|---|---|---|---|---|---|---|---|---|
| Ruta A — Comercial y Preventa | 4 | 36 | 36 | 0 | 0 | 0 | 4 |
| Ruta B — Ingeniería e Integración | 4 | 36 | 22 | 14 | 0 | 0 | 4 |
| Ruta C — Ejecución y Postventa | 5 | 45 | 13 | 23 | 9 | 0 | 5 |
| Ruta D — Gemelos Digitales | 2 | 9 | 9 | 0 | 0 | 0 | 0 |
| Ruta E — Agentes y Automatización | 9 | 144 | 16 | 16 | 112 | 0 | 9 |
| Ruta F — Fabricantes y Plataformas | 19 | 266 | 44 | 110 | 112 | 0 | 19 |
| — | 22 | 172 | 0 | 0 | 172 | 0 | 21 |

### 4.2 Tabla completa por curso

**Ruta A — Comercial y Preventa**

| ch | Curso | Art. | Estado imágenes | Cert/doc |
|---|---|---|---|---|
| 32 | El negocio del integrador de tecnología | 9 | ✅9 | 1 |
| 33 | Levantamiento técnico y site survey | 9 | ✅9 | 1 |
| 34 | Diseño de solución y BoM | 9 | ✅9 | 1 |
| 35 | Propuesta técnica, licitaciones y ética comercial | 9 | ✅9 | 1 |

**Ruta B — Ingeniería e Integración**

| ch | Curso | Art. | Estado imágenes | Cert/doc |
|---|---|---|---|---|
| 36 | Interoperabilidad y protocolos de integración | 9 | ✅6 🟠3 | 1 |
| 37 | Diseño de seguridad electrónica por capas | 9 | ✅9 | 1 |
| 38 | Normatividad y estándares para integradores | 9 | ✅7 🟠2 | 1 |
| 39 | Centros de control, PSIM y operación | 9 | 🟠9 | 1 |

**Ruta C — Ejecución y Postventa**

| ch | Curso | Art. | Estado imágenes | Cert/doc |
|---|---|---|---|---|
| 40 | Gestión de proyectos de integración | 9 | 🟠9 | 1 |
| 41 | Comisionamiento, pruebas y entrega | 9 | ✅9 | 1 |
| 42 | SLA, soporte y mantenimiento | 9 | 🟠9 | 1 |
| 43 | Finanzas y rentabilidad del proyecto | 9 | ✅4 🟠5 | 1 |
| 44 | Proyecto capstone: integración de punta a punta | 9 | 🟡9 | 1 |

**Ruta D — Gemelos Digitales**

| ch | Curso | Art. | Estado imágenes | Cert/doc |
|---|---|---|---|---|
| 45 | Gemelos Digitales — Fundamentos y casos de uso | 5 | ✅5 | 0 |
| 46 | Gemelos Digitales — Proveedores, socios y cómo elegir | 4 | ✅4 | 0 |

**Ruta E — Agentes y Automatización**

| ch | Curso | Art. | Estado imágenes | Cert/doc |
|---|---|---|---|---|
| 48 | LangGraph — Fundamentos y grafos de estado | 16 | ✅16 | 1 |
| 49 | LangGraph — Herramientas, memoria y humanos en el bucle | 16 | 🟠16 | 1 |
| 50 | LangGraph — Producción: evaluación, observabilidad y despliegue | 16 | 🟡16 | 1 |
| 51 | n8n — Fundamentos y automatización visual | 16 | 🟡16 | 1 |
| 52 | n8n — Integraciones, webhooks y subflujos | 16 | 🟡16 | 1 |
| 53 | n8n — Producción: colas, errores y gobierno | 16 | 🟡16 | 1 |
| 54 | OpenClaw — Fundamentos y arquitectura de agentes | 16 | 🟡16 | 1 |
| 55 | OpenClaw — Skills, herramientas y canales | 16 | 🟡16 | 1 |
| 56 | OpenClaw — Operación: multiagente, cron y automatización | 16 | 🟡16 | 1 |

**Ruta F — Fabricantes y Plataformas**

| ch | Curso | Art. | Estado imágenes | Cert/doc |
|---|---|---|---|---|
| 47 | SAS Viya — Fundamentos y arquitectura | 14 | ✅14 | 1 |
| 57 | SAS Viya — Analítica, modelos y decisiones | 14 | ✅14 | 1 |
| 58 | SAS Viya — Operación, gobierno y buenas prácticas | 14 | ✅5 🟠9 | 1 |
| 59 | Hexagon — Fundamentos: HxGN y seguridad | 14 | 🟠14 | 1 |
| 60 | Hexagon — Integración, PSIM y operación | 14 | 🟠14 | 1 |
| 61 | Cisco — Fundamentos de red empresarial | 14 | 🟠14 | 1 |
| 62 | Cisco — Seguridad y operación | 14 | 🟠14 | 1 |
| 63 | Cisco — Automatización y control | 14 | 🟠14 | 1 |
| 64 | Fortinet — Fundamentos de FortiOS | 14 | ✅10 🟠4 | 1 |
| 65 | Fortinet — FortiGate en producción y FortiManager | 14 | ✅1 🟠13 | 1 |
| 66 | Fortinet — Seguridad operativa y respuesta | 14 | 🟠14 | 1 |
| 67 | OpenAI — ChatGPT en Windows: trabajo diario | 14 | 🟡14 | 1 |
| 68 | OpenAI — Codex: desarrollo asistido y agentes de código | 14 | 🟡14 | 1 |
| 69 | Google — Gemini CLI y Code Assist | 14 | 🟡14 | 1 |
| 70 | Google — Gemini Enterprise y agentes en Vertex AI | 14 | 🟡14 | 1 |
| 71 | Microsoft — Azure AI Foundry: modelos y agentes | 14 | 🟡14 | 1 |
| 72 | Microsoft — Copilot Studio y Copilot en Microsoft 365 | 14 | 🟡14 | 1 |
| 73 | NVIDIA — NIM y despliegue de modelos en GPU | 14 | 🟡14 | 1 |
| 74 | NVIDIA — Omniverse e IA física | 14 | 🟡14 | 1 |

**—**

| ch | Curso | Art. | Estado imágenes | Cert/doc |
|---|---|---|---|---|
| 8 | Introducción a la Inteligencia Artificial | 0 | — | 2 |
| 9 | n8n | 0 | — | 2 |
| 12 | Inducción INT — Bienvenida al equipo | 9 | 🟡9 | 1 |
| 13 | Uso del portal (Odoo) para colaboradores | 6 | 🟡6 | 0 |
| 14 | Seguridad de la información — nivel básico | 6 | 🟡6 | 0 |
| 15 | Fundamentos de Inteligencia Artificial y Machine Learning | 11 | 🟡11 | 1 |
| 16 | IA Generativa, LLMs y Prompt Engineering | 10 | 🟡10 | 1 |
| 17 | RAG — Recuperación Aumentada por Generación | 10 | 🟡10 | 1 |
| 18 | Agentes de IA y Orquestación | 9 | 🟡9 | 1 |
| 19 | DevOps para IA — Infraestructura y Despliegue | 10 | 🟡10 | 1 |
| 20 | Analítica de Datos con SAS | 9 | 🟡9 | 1 |
| 21 | Fundamentos de Telecomunicaciones | 9 | 🟡9 | 1 |
| 22 | Redes Satelitales LEO y Starlink | 9 | 🟡9 | 1 |
| 23 | Cableado Estructurado de Redes | 9 | 🟡9 | 1 |
| 24 | Equipos de Red Cisco | 9 | 🟡9 | 1 |
| 25 | Equipos de Red Fortinet | 9 | 🟡9 | 1 |
| 26 | Videovigilancia — Cámaras y Equipos | 9 | 🟡9 | 1 |
| 27 | LPR — Reconocimiento Automático de Placas | 9 | 🟡9 | 1 |
| 28 | Marcas Líderes de Videovigilancia | 9 | 🟡9 | 1 |
| 29 | Ciberseguridad — Fundamentos | 10 | 🟡10 | 1 |
| 30 | Hexagon — Safety & Infrastructure | 9 | 🟡9 | 1 |
| 31 | 📋 Plan de Capacitación INT | 1 | 🟡1 | 0 |

**Notas del inventario:**
- Ruta A (36 art) y Ruta D (9 art) están 100% completas.
- Huecos reales en B, C, F: cursos enteros sin imágenes publicadas (ch39 Centros de control, ch42 SLA, ch59–63 Hexagon/Cisco, ch66 Fortinet). El patrón "parcial" suele ser que faltan solo `s1/s3` o `hero/s2/s4` → publish cortado a la mitad.
- E y F (mitad de cursos) + C capstone siguen en HUB-legacy.
- CSV detallado lección-por-lección (770 filas): `tmp/odoo_inventario_imagenes.csv`.

## 5. SPEC de contenido y diseño — REQUISITOS DE JAVI (consolidados)

Esta es la parte más importante. Consolida TODO lo que Javi ha pedido sobre cómo deben verse las lecciones y generarse las imágenes. Cualquier script nuevo o cambio debe cumplir ESTO.

### 5.1 Layout de lección 65/35 ✅ (ya aplicado)
- Cada bloque de lección va en grid **imagen 65% / texto 35%**: `.int-lec .blk` con `grid-template-columns:minmax(0,1.85fr) minmax(0,1fr)`; responsive → se apila debajo de 820px.
- CSS vive en la constante `CSS` de `push_ruta_a.py`. Clases `.int-lec .kicker/.lead/.blk/.take`.

### 5.2 Dos imágenes por cada una: light + dark ⚠️ (parcial)
- **Cada `ra{id}_{bloque}` debe existir en dos variantes:** `ra{id}_{bloque}.jpg` (light) y `ra{id}_{bloque}_dark.jpg` (dark). Aplicar a TODOS los bloques (hero, s1..s4).
- El tema intercambia según modo (`data-bs-theme` dark/light). `gen_lesson_art_qwen.py` ya emite `variant` LIGHT/DARK.
- **PENDIENTE:** asegurar el par `_dark` por cada `ra{id}_{bloque}` y backfill de los que falten.

### 5.3 Click en la imagen → se hace más grande (lightbox) 🔴 (NUEVO — pendiente)
- Al hacer click en la imagen de un bloque de lección, debe abrirse en grande (overlay/lightbox a pantalla completa o casi).
- Requisitos: cerrar con **X**, **click fuera**, y tecla **Esc**; mantener la variante light/dark activa en el lightbox; que no rompa el grid 65/35.
- Dónde: en el render de `push_ruta_a.py` (HTML/CSS/JS inline) y/o en `int_theme.js`.

### 5.4 Más texto DENTRO de las imágenes 🔴 (NUEVO — pendiente)
- Las imágenes generadas deben llevar **más texto integrado y legible**: título del bloque, labels, bullets, números de paso, diagramas con anotaciones. No ilustración abstracta sin palabras.
- El brief de cada imagen (`ruta_a_briefs.py` / `ruta_a_briefs_complete.json`) debe especificar el texto EXACTO que va dentro de cada imagen, en el estilo isométrico de la Ruta A.
- El prompt de generación (Qwen-Image 2.1) debe pedir ese texto de forma explícita y que sea legible (sin typos, contraste alto).

### 5.5 HTML descriptivo, no solo títulos 🔴 (NUEVO — pendiente)
- El `html_content` de cada lección debe tener **texto sustancioso**: párrafos descriptivos completos en `lead` y en el bloque de texto, no frases-cáscara ni solo el título/kicker.
- `ruta_a_texts.py` / `ruta_a_texts.json` deben producir texto de 2–4 oraciones por bloque, con valor didáctico real (definiciones, ejemplos, pasos, por qué importa).

### 5.6 UX/UI del frontend Odoo (feedback Javi, 02-nov + 04-nov)
- **Light/dark** (toggle sol/luna en header) — ✅ ya en `int_theme` (data-bs-theme + swap light/dark). Confirma alcance: todo el sitio (ya aplicado) vs solo lecciones.
- **Menús superiores sticky** — header principal + nav de curso/lección no se mueven al scroll.
- **Al salir de fullscreen** — mantener visible la nav del curso (breadcrumb + lista de lecciones), no solo el menú del sitio.
- **Menú principal** — breadcrumb (Cursos/categoría/curso) + buscador «Buscar cursos» (confirmar si ambos o solo buscador).
- **Footer** — quitar "Powered by Odoo" (deuda).
- Tema activo `theme_bewise`, website 1 «Int Hub». `int_theme` en host `/root/odoo/addons`, container `/mnt/extra-addons`.

## 6. Pipeline de contenido (flujo y comandos)

**Canonical en el workspace:** `scripts/media/` + estado en `tmp/`. Python del pipeline: `.venv/bin/python` (Pillow + requests). ComfyUI: `COMFY_BASE=http://127.0.0.1:8198` (GPU0) o `:8199` (GPU1).

Flujo (nueva tanda):
1. `ruta_a_briefs.py` → `tmp/ruta_a_briefs.json` (brief por lección, DeepSeek).
2. `ruta_a_texts.py` → `tmp/ruta_a_texts.json` (texto por lección, DeepSeek).
3. Imágenes (ComfyUI + Qwen-Image 2.1): `gen_lesson_art_qwen.py` + `comfy_run.py`. Copiar PNG a `tmp/qa/ruta_a/img/` antes del build.
4. `build_ruta_a.py` → `tmp/ruta-a-site/` (index + curso-*.html + leccion-*.html + img/*.jpg light/dark).
5. Publicar: `rsync -az --chown=inttuser:inttuser -e "ssh" tmp/ruta-a-site/ linode-intt:/opt/ia-intt/html/ruta-a/` (URL `https://www.intt2hub.com/ia/ruta-a/`).
6. Integrar en Odoo: `push_ruta_a.py` (idempotente por `(channel_id, name, slide_category)`, requiere túnel 8069; `--dry-run` para validar).

**Gotchas:** 4 lecciones tienen solo 3 bloques → 4 PNGs huérfanos (`ra272_s4`, `ra278_s4`, `ra284_s4`, `ra292_s4`), no es bug. Backups de nginx fuera de `sites-enabled/`. Los scripts de laboratorio usan rutas del host local.

## 7. Cómo continuar (próximos pasos, en orden)

1. **Implementar el SPEC 5.3–5.5** (lightbox, más texto en imágenes, HTML descriptivo) en `push_ruta_a.py` + `int_theme.js` + los generadores de briefs/textos.
2. **Cerrar los huecos de imágenes** del inventario §4: regenerar/publicar las faltantes de B, C y F (empezar por los cursos en 🔴/🟠: ch39, ch42, ch59–63, ch66). Backfill de pares `_dark` (§5.2).
3. **Migrar HUB-legacy** de E/F/C capstone al pipeline de rutas (imágenes `ra{id}_{bloque}` light/dark).
4. Confirmar con Javi el alcance del frontend (§5.6) antes de tocar prod.

## 8. Reglas universales (heredadas)

- **Veracidad:** nunca inventar datos, rutas, cifras ni APIs. Verificar y citar fuente.
- **Memoria:** cerrar trabajo relevante actualizando `MEMORY.md` (largo plazo) + `memory/YYYY-MM-DD.md` (diario).
- **Sin snapshot no hay cirugía** en producción; plan de rollback escrito.
- Bitácora compartida con main: `/home/ailab/.openclaw/shared/agent-activity.md` (1 línea por tema, solo lo que main deba saber).
