{ "meta": { "proyecto": "PymesBot", "repo_url": "https://gitea.cbcren.online/renato97", "version": "1.0", "creado": "2026-02-17", "descripcion": "Cola de tareas para construcción automática de PymesBot por bots IA. Procesar en orden de sprint y prioridad. No saltar tareas con dependencias pendientes." }, "tareas": [ { "id": "P1-T01", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 1, "titulo": "Crear estructura base del proyecto backend", "descripcion": "Crear todos los archivos vacíos con la estructura de carpetas definida en la sección 6 del spec. Crear: requirements.txt con las dependencias exactas de la sección 11, Dockerfile del backend de la sección 11, .gitignore apropiado para Python/Docker.", "archivo_destino": "pymesbot-backend/", "archivos_a_crear": [ "pymesbot-backend/requirements.txt", "pymesbot-backend/Dockerfile", "pymesbot-backend/.gitignore", "pymesbot-backend/backend/templates/.gitkeep", "pymesbot-backend/data/uploads/.gitkeep" ], "contexto_spec": "Secciones 6 y 11 de 01_PYMESBOT_PROJECT_SPEC.md", "dependencias": [], "status": "pending", "intentos": 1, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": "Respuesta inesperada: {\"id\":\"05e3cf84a03c3ec07d36cbe8c6eb340d\",\"type\":\"message\",\"role\":\"assistant\",\"model\":\"MiniMax-M2.5\",\"content\":[{\"thinking\":\"The user input seems to be a template placeholder: `={{ $json.prompt }}`. Th" }, { "id": "P1-T02", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 2, "titulo": "Implementar db.py — helpers de SQLite", "descripcion": "Crear pymesbot-backend/backend/db.py con: función get_db() que devuelve conexión aiosqlite, función init_db() que crea las tablas si no existen usando el schema completo de la sección 7, función get_config(clave) que lee de la tabla config. Usar aiosqlite para todas las operaciones. El path de la DB es /app/data/stock.db.", "archivo_destino": "pymesbot-backend/backend/db.py", "archivos_a_crear": [ "pymesbot-backend/backend/db.py" ], "contexto_spec": "Sección 7 de 01_PYMESBOT_PROJECT_SPEC.md — esquema SQL completo con las 4 tablas: productos, ventas, promociones, config", "dependencias": [ "P1-T01" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T03", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 3, "titulo": "Implementar models.py — Pydantic models", "descripcion": "Crear pymesbot-backend/backend/models.py con todos los modelos Pydantic necesarios para los endpoints: ProductoResponse, VentaConfirmarRequest, VentaConfirmarResponse, StockSearchResponse, ComboArmarRequest, ComboArmarResponse, PromoResponse, StatsResponse, ConfigUpdate. Basarse en los schemas JSON de la sección 8 del spec.", "archivo_destino": "pymesbot-backend/backend/models.py", "archivos_a_crear": [ "pymesbot-backend/backend/models.py" ], "contexto_spec": "Sección 8 de 01_PYMESBOT_PROJECT_SPEC.md — todos los request/response JSON de cada endpoint", "dependencias": [ "P1-T01" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T04", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 4, "titulo": "Implementar auth.py — autenticación PIN y admin", "descripcion": "Crear pymesbot-backend/backend/auth.py con: función verify_vendor_pin(pin) que compara con la config de la DB, función verify_admin_password(password), dependencia FastAPI get_current_vendor() para proteger rutas del chat, dependencia get_current_admin() para proteger rutas admin. Autenticación simple sin JWT — usar cookies de sesión o Basic Auth.", "archivo_destino": "pymesbot-backend/backend/auth.py", "archivos_a_crear": [ "pymesbot-backend/backend/auth.py" ], "contexto_spec": "Sección 10 de 01_PYMESBOT_PROJECT_SPEC.md — Vista Vendedor: acceso con PIN 4 dígitos. Vista Admin: usuario admin + contraseña.", "dependencias": [ "P1-T02" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T05", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 5, "titulo": "Implementar tools.py — endpoint GET /stock/search", "descripcion": "Crear pymesbot-backend/backend/tools.py con el router de stock. Implementar GET /stock/search con parámetros q (string) y limit (int, default 5). Lógica de búsqueda en 3 pasos: 1) LIKE exacto, 2) AND de palabras, 3) OR de palabras. Solo productos activos. Devolver formato exacto de la sección 8. Incluir campo sugerencias cuando no hay resultados.", "archivo_destino": "pymesbot-backend/backend/tools.py", "archivos_a_crear": [ "pymesbot-backend/backend/tools.py" ], "contexto_spec": "Sección 8 de 01_PYMESBOT_PROJECT_SPEC.md — endpoint GET /stock/search con la lógica de búsqueda de 3 pasos y el formato de respuesta JSON exacto", "dependencias": [ "P1-T02", "P1-T03" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T06", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 6, "titulo": "Implementar tools.py — endpoint POST /venta/confirmar", "descripcion": "Agregar al router de ventas en tools.py el endpoint POST /venta/confirmar. Validaciones obligatorias: producto existe y activo, cantidad > 0, stock >= cantidad. Si pasa: INSERT en ventas, UPDATE stock en productos. Devolver formato exacto de la sección 8 incluyendo stock_anterior y stock_nuevo.", "archivo_destino": "pymesbot-backend/backend/tools.py", "archivos_a_crear": [], "contexto_spec": "Sección 8 de 01_PYMESBOT_PROJECT_SPEC.md — endpoint POST /venta/confirmar con todas las validaciones y el formato de respuesta", "dependencias": [ "P1-T05" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T07", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 7, "titulo": "Implementar tools.py — endpoint GET /health", "descripcion": "Agregar endpoint GET /health al main.py. Devolver: {status: 'ok', negocio: nombre_negocio_de_config}. Este endpoint NO requiere autenticación. Es el que usa el healthcheck de Docker.", "archivo_destino": "pymesbot-backend/backend/main.py", "archivos_a_crear": [ "pymesbot-backend/backend/main.py" ], "contexto_spec": "Sección 8 de 01_PYMESBOT_PROJECT_SPEC.md — /health endpoint. Sección 11 — healthcheck en docker-compose.", "dependencias": [ "P1-T02", "P1-T03", "P1-T04", "P1-T05" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T08", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 8, "titulo": "Implementar WebSocket /chat/ws/{session_id}", "descripcion": "Agregar en main.py el endpoint WebSocket /chat/ws/{session_id}. El handler recibe mensajes del frontend, mantiene historial en memoria (dict session_id → lista de mensajes, máximo 20 turnos, expirar después de 30 min de inactividad). Por ahora el bot puede ser un echo simple o respuesta hardcodeada — la integración real con PicoClaw es P2-T01. Enviar {typing: true} al recibir, {msg: '...', typing: false} al responder.", "archivo_destino": "pymesbot-backend/backend/main.py", "archivos_a_crear": [], "contexto_spec": "Sección 8 de 01_PYMESBOT_PROJECT_SPEC.md — WebSocket /chat/ws/{session_id} con el protocolo de mensajes exacto", "dependencias": [ "P1-T07" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T09", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 9, "titulo": "Implementar parser de Excel/CSV para importar stock", "descripcion": "Agregar en tools.py el endpoint POST /stock/importar. Aceptar archivos .xlsx y .csv. Detección automática de columnas case-insensitive: nombre/producto/descripcion → nombre, precio/precio_venta/price → precio, stock/cantidad/qty → stock (default 0), categoria/rubro/category → categoria (default 'general'), marca/brand → marca, codigo/ean/barcode → codigo. Modos: 'reemplazar' borra todo primero, 'actualizar' hace upsert. Devolver {importados, actualizados, errores, errores_detalle}.", "archivo_destino": "pymesbot-backend/backend/tools.py", "archivos_a_crear": [], "contexto_spec": "Sección 8 de 01_PYMESBOT_PROJECT_SPEC.md — endpoint POST /stock/importar con la lógica de detección de columnas y los modos reemplazar/actualizar", "dependencias": [ "P1-T05" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T10", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 10, "titulo": "Crear template HTML base y vista vendedor (chat)", "descripcion": "Crear pymesbot-backend/backend/templates/base.html con el layout base: navbar con nombre del negocio, CSS variables para colores, responsive. Crear templates/chat.html extendiendo base.html: layout dividido (chat izquierda + resumen del día derecha), área de mensajes del chat, input de texto + botón enviar, panel de resumen (ventas del día + alertas de stock bajo). El JS del chat conecta al WebSocket /chat/ws/{session_id} y maneja los eventos typing/msg.", "archivo_destino": "pymesbot-backend/backend/templates/", "archivos_a_crear": [ "pymesbot-backend/backend/templates/base.html", "pymesbot-backend/backend/templates/chat.html" ], "contexto_spec": "Sección 10 de 01_PYMESBOT_PROJECT_SPEC.md — Vista Vendedor con el layout ASCII y las características detalladas del chat", "dependencias": [ "P1-T08" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T11", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 11, "titulo": "Crear dashboard.py y vista admin básica", "descripcion": "Crear pymesbot-backend/backend/dashboard.py con las rutas del panel admin. Ruta GET /admin sirve el template admin.html con autenticación. La vista admin básica solo necesita: sección de estadísticas del día (llamar a /stats/ventas?periodo=hoy) y sección de upload de Excel (formulario que llama a POST /stock/importar). Las secciones avanzadas (promociones, historial) son del sprint 2.", "archivo_destino": "pymesbot-backend/backend/dashboard.py", "archivos_a_crear": [ "pymesbot-backend/backend/dashboard.py", "pymesbot-backend/backend/templates/admin.html" ], "contexto_spec": "Sección 10 de 01_PYMESBOT_PROJECT_SPEC.md — Vista Dueño/Admin, primeras dos secciones: Dashboard principal y Gestión de stock", "dependencias": [ "P1-T04", "P1-T10" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T12", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 12, "titulo": "Implementar GET /stats/ventas", "descripcion": "Agregar endpoint GET /stats/ventas en tools.py con parámetro periodo ('hoy'|'semana'|'mes'). Calcular: total_ventas (count), total_pesos (sum), ticket_promedio, top 5 productos más vendidos con cantidad y total, comparación con período anterior (misma duración hacia atrás). Devolver formato exacto de la sección 8.", "archivo_destino": "pymesbot-backend/backend/tools.py", "archivos_a_crear": [], "contexto_spec": "Sección 8 de 01_PYMESBOT_PROJECT_SPEC.md — endpoint GET /stats/ventas con el formato de respuesta JSON completo", "dependencias": [ "P1-T06" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P1-T13", "proyecto": "pymesbot-backend", "sprint": 1, "prioridad": 13, "titulo": "Crear docker-compose.yml template del cliente", "descripcion": "Crear pymesbot-backend/docker-compose.template.yml con el docker-compose del cliente según la sección 11 del spec. También crear el schema.sql con el SQL completo de la sección 7 para inicialización de la DB.", "archivo_destino": "pymesbot-backend/", "archivos_a_crear": [ "pymesbot-backend/docker-compose.template.yml", "pymesbot-backend/schema.sql" ], "contexto_spec": "Secciones 7 y 11 de 01_PYMESBOT_PROJECT_SPEC.md — docker-compose completo con healthcheck y schema SQL completo con índices e inserts iniciales", "dependencias": [ "P1-T01" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P2-T01", "proyecto": "pymesbot-backend", "sprint": 2, "prioridad": 1, "titulo": "Integrar PicoClaw en el WebSocket de chat", "descripcion": "Reemplazar el echo del WebSocket por la integración real con PicoClaw. El backend llama internamente al proceso PicoClaw pasándole: el historial de conversación, el system prompt desde la config de la DB, las 4 herramientas definidas en la sección 9. Cuando PicoClaw llama una herramienta, el backend ejecuta el endpoint correspondiente (/stock/search, /venta/confirmar, /combo/armar, /promo/activas) y devuelve el resultado a PicoClaw. El formato del system prompt es el de la sección 9.", "archivo_destino": "pymesbot-backend/backend/main.py", "archivos_a_crear": [ "pymesbot-backend/backend/picoclaw_bridge.py" ], "contexto_spec": "Sección 9 de 01_PYMESBOT_PROJECT_SPEC.md — config completa de PicoClaw, system prompt, y las 4 herramientas con sus schemas JSON", "dependencias": [ "P1-T08", "P1-T05", "P1-T06" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P2-T02", "proyecto": "pymesbot-backend", "sprint": 2, "prioridad": 2, "titulo": "Implementar POST /combo/armar", "descripcion": "Crear endpoint POST /combo/armar en tools.py. Recibe presupuesto (required), edad (optional int), genero (optional: 'nena'|'neno'|null). Lógica: filtrar productos por categorías configuradas en config combo_categorias y stock > 0. Aplicar criterios de edad: <=6 = inicial, 7-10 = primaria, 11-13 = primaria sup, >=14 = secundaria. Aplicar preferencia de género en nombres/colores. Ordenar por esencialidad hardcodeada. Armar combo hasta 95% del presupuesto. Devolver formato exacto de sección 8 incluyendo campo incluido y esencial por producto.", "archivo_destino": "pymesbot-backend/backend/tools.py", "archivos_a_crear": [], "contexto_spec": "Sección 8 de 01_PYMESBOT_PROJECT_SPEC.md — endpoint POST /combo/armar con toda la lógica de edad, género y armado hasta el 95% del presupuesto", "dependencias": [ "P1-T05" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P2-T03", "proyecto": "pymesbot-backend", "sprint": 2, "prioridad": 3, "titulo": "Implementar endpoints de promociones", "descripcion": "Agregar en tools.py: GET /promo/activas (devuelve promos donde activa=1 y fecha_fin >= hoy o fecha_fin es null), POST /promo/crear (solo admin, valida body con Pydantic, inserta en DB), PUT /promo/{id}/toggle (activa/desactiva). Aplicar promociones activas automáticamente en /stock/search: si hay promo para el producto, incluir campo promo_activa en la respuesta.", "archivo_destino": "pymesbot-backend/backend/tools.py", "archivos_a_crear": [], "contexto_spec": "Sección 8 de 01_PYMESBOT_PROJECT_SPEC.md — endpoints GET /promo/activas y POST /promo/crear con los formatos JSON", "dependencias": [ "P1-T05", "P1-T04" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P2-T04", "proyecto": "pymesbot-backend", "sprint": 2, "prioridad": 4, "titulo": "Implementar GET /stock/alertas y GET /venta/historial", "descripcion": "Agregar en tools.py: GET /stock/alertas que devuelve productos con stock < alerta_stock_minimo de la config. GET /venta/historial con filtros fecha_desde, fecha_hasta, producto_id, vendedor, limit (max 1000), offset. JOIN con productos para incluir nombre del producto en cada venta. Devolver suma_total del período.", "archivo_destino": "pymesbot-backend/backend/tools.py", "archivos_a_crear": [], "contexto_spec": "Sección 8 de 01_PYMESBOT_PROJECT_SPEC.md — endpoints GET /stock/alertas y GET /venta/historial", "dependencias": [ "P1-T06" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P2-T05", "proyecto": "pymesbot-backend", "sprint": 2, "prioridad": 5, "titulo": "Completar vista admin — promociones e historial", "descripcion": "Agregar a admin.html las secciones de Promociones e Historial de ventas. Promociones: lista con toggle activo/inactivo, formulario de nueva promo con todos los campos. Historial: tabla con filtros de fecha (date picker nativo HTML), botón exportar CSV que llama al backend. Agregar sección Configuración: formulario para cambiar PIN del vendedor, contraseña admin, nombre del negocio, umbral de alertas.", "archivo_destino": "pymesbot-backend/backend/templates/admin.html", "archivos_a_crear": [], "contexto_spec": "Sección 10 de 01_PYMESBOT_PROJECT_SPEC.md — Vista Admin, secciones Promociones, Historial de ventas y Configuración", "dependencias": [ "P1-T11", "P2-T03", "P2-T04" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "P2-T06", "proyecto": "pymesbot-backend", "sprint": 2, "prioridad": 6, "titulo": "Hacer la UI responsive para tablet y móvil", "descripcion": "Revisar base.html, chat.html y admin.html para que funcionen bien en pantallas desde 768px. En chat.html móvil: el panel de resumen se colapsa con un botón. En admin.html móvil: las tablas hacen scroll horizontal. Usar media queries CSS, sin frameworks. Testear mentalmente con 768px, 1024px y 1280px de ancho.", "archivo_destino": "pymesbot-backend/backend/templates/", "archivos_a_crear": [], "contexto_spec": "Sección 10 de 01_PYMESBOT_PROJECT_SPEC.md — Consideraciones de diseño: funcionar en tablet 10\" y PC de escritorio", "dependencias": [ "P1-T10", "P1-T11", "P2-T05" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I1-T01", "proyecto": "pymesbot-installer", "sprint": 1, "prioridad": 1, "titulo": "Crear estructura base del proyecto installer", "descripcion": "Crear la estructura de carpetas completa del instalador según la sección 3 del spec del instalador. Crear: Dockerfile, .dockerignore, requirements.txt con las dependencias de la sección 4, archivos __init__.py vacíos en app/. NO implementar lógica aún, solo la estructura.", "archivo_destino": "pymesbot-installer/", "archivos_a_crear": [ "pymesbot-installer/Dockerfile", "pymesbot-installer/.dockerignore", "pymesbot-installer/requirements.txt", "pymesbot-installer/app/__init__.py", "pymesbot-installer/static/.gitkeep" ], "contexto_spec": "Secciones 3, 4 y 5 de 02_PYMESBOT_INSTALLER_SPEC.md — estructura de archivos, stack y Dockerfile completo", "dependencias": [], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I1-T02", "proyecto": "pymesbot-installer", "sprint": 1, "prioridad": 2, "titulo": "Implementar state.py y security.py", "descripcion": "Crear app/state.py con las funciones save_session, get_session, clear_session exactamente como están definidas en la sección 13 del spec. SESSION_TIMEOUT = 1800. Crear app/security.py con: generación del INSTALL_TOKEN al importar el módulo (secrets.token_urlsafe(16)), función async validar_sudo(password) que ejecuta 'echo PASSWORD | sudo -S whoami' y devuelve (bool, str). Manejar los 3 casos de error: incorrect password, not in sudoers, otro error.", "archivo_destino": "pymesbot-installer/app/", "archivos_a_crear": [ "pymesbot-installer/app/state.py", "pymesbot-installer/app/security.py" ], "contexto_spec": "Sección 13 de 02_PYMESBOT_INSTALLER_SPEC.md — código exacto de state.py y security.py", "dependencias": [ "I1-T01" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I1-T03", "proyecto": "pymesbot-installer", "sprint": 1, "prioridad": 3, "titulo": "Implementar detect.py — detección del entorno", "descripcion": "Crear app/detect.py con: función async run_cmd(cmd, timeout) exactamente como está en la sección 6, dataclasses ComponentStatus/ClienteExistente/DetectionResult, función async detectar_entorno() que verifica en orden: Docker (docker --version), Nginx (nginx -v 2>&1), Certbot (certbot --version), /opt/pymesbot (os.path.exists), red pymesbot_net (docker network ls). Listar clientes leyendo subdirectorios de /opt/pymesbot excluyendo nginx/scripts/archivos. Para cada cliente leer su .env. Determinar modo A o B. Calcular siguiente puerto disponible desde 8200.", "archivo_destino": "pymesbot-installer/app/detect.py", "archivos_a_crear": [ "pymesbot-installer/app/detect.py" ], "contexto_spec": "Sección 6 completa de 02_PYMESBOT_INSTALLER_SPEC.md — todas las funciones, dataclasses y lógica de detección", "dependencias": [ "I1-T01" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I1-T04", "proyecto": "pymesbot-installer", "sprint": 1, "prioridad": 4, "titulo": "Implementar main.py — FastAPI esqueleto + token de seguridad", "descripcion": "Crear app/main.py con: FastAPI app, evento startup que imprime el token en la terminal (formato exacto de la sección 10), dependencia verificar_token que revisa query param o cookie, ruta GET /install que verifica token y sirve static/index.html, ruta GET /install/detect que llama detectar_entorno() y devuelve JSON, ruta POST /install/validate-sudo, ruta POST /install/check-slug con regex validación, ruta POST /install/start. Sin WebSocket aún (eso es I1-T06).", "archivo_destino": "pymesbot-installer/app/main.py", "archivos_a_crear": [ "pymesbot-installer/app/main.py" ], "contexto_spec": "Sección 10 de 02_PYMESBOT_INSTALLER_SPEC.md — código completo de main.py con todas las rutas excepto el WebSocket", "dependencias": [ "I1-T02", "I1-T03" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I1-T05", "proyecto": "pymesbot-installer", "sprint": 1, "prioridad": 5, "titulo": "Crear el wizard HTML completo (pasos 0 a 6)", "descripcion": "Crear static/index.html con el wizard completo de 6 pasos. Diseño oscuro con la paleta de colores exacta de la sección 11: --bg #080E1A, --accent #00D4FF, --accent2 #00FF9D. Fuentes: Space Grotesk (body) + IBM Plex Mono (código/slugs). Layout: header + sidebar con pasos + panel de contenido. Los 6 pasos con toda la lógica JS: auto-detect al cargar, formularios con validación, auto-generación del slug (función nombreASlug de la sección 11), check de slug disponible al perder el foco, checkbox de confirmación habilita botón. Por ahora el paso 5 (progreso) puede ser mock — el WebSocket real es I1-T06.", "archivo_destino": "pymesbot-installer/static/index.html", "archivos_a_crear": [ "pymesbot-installer/static/index.html", "pymesbot-installer/static/style.css", "pymesbot-installer/static/wizard.js" ], "contexto_spec": "Sección 11 completa de 02_PYMESBOT_INSTALLER_SPEC.md — paleta de colores, fuentes, layout, los 6 pasos con todos los campos y lógica JS", "dependencias": [ "I1-T04" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I1-T06", "proyecto": "pymesbot-installer", "sprint": 1, "prioridad": 6, "titulo": "Implementar WebSocket /install/ws/{session_id} en main.py", "descripcion": "Agregar a main.py el endpoint WebSocket /install/ws/{session_id} exactamente como está en la sección 10. El handler recupera la sesión, determina el modo (A o B), llama instalar_infraestructura si es modo A, luego llama setup_cliente. Usa progress_callback para enviar eventos. Envía evento 'done' al finalizar con url y credentials. En caso de excepción: intenta rollback y cierra el WebSocket.", "archivo_destino": "pymesbot-installer/app/main.py", "archivos_a_crear": [], "contexto_spec": "Sección 10 de 02_PYMESBOT_INSTALLER_SPEC.md — código completo del WebSocket handler", "dependencias": [ "I1-T04", "I1-T05" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I2-T01", "proyecto": "pymesbot-installer", "sprint": 2, "prioridad": 1, "titulo": "Implementar templates_engine.py", "descripcion": "Crear app/templates_engine.py con las 4 funciones: generar_env_cliente, generar_docker_compose_cliente, generar_picoclaw_config, generar_nginx_conf, más la función escribir_archivo. Crear los 4 archivos Jinja2 en app/config_templates/ con el contenido exacto de la sección 12: env_client.j2, docker-compose.client.yml.j2, picoclaw_config.json.j2 (con el system prompt completo de la sección 9 del spec principal), nginx_site.conf.j2. También crear config_templates/schema.sql con el SQL completo de la sección 7 del spec principal.", "archivo_destino": "pymesbot-installer/app/", "archivos_a_crear": [ "pymesbot-installer/app/templates_engine.py", "pymesbot-installer/app/config_templates/env_client.j2", "pymesbot-installer/app/config_templates/docker-compose.client.yml.j2", "pymesbot-installer/app/config_templates/picoclaw_config.json.j2", "pymesbot-installer/app/config_templates/nginx_site.conf.j2", "pymesbot-installer/app/config_templates/schema.sql" ], "contexto_spec": "Sección 9 de 02_PYMESBOT_INSTALLER_SPEC.md — código de templates_engine.py. Sección 12 — contenido de los 4 templates Jinja2. Sección 7 de 01_PYMESBOT_PROJECT_SPEC.md — schema SQL completo.", "dependencias": [ "I1-T01" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I2-T02", "proyecto": "pymesbot-installer", "sprint": 2, "prioridad": 2, "titulo": "Implementar client_setup.py — alta de cliente (pasos C1 a C9)", "descripcion": "Crear app/client_setup.py con: dataclass ClientConfig, función async setup_cliente(config, progress_callback) con los 9 pasos (C1 mkdir, C2 generar configs, C3 init DB con sqlite3, C4 copiar backend, C5 nginx conf + reload, C6 certbot SSL con manejo de errores específicos de DNS y rate limit, C7 docker compose up, C8 health check con 5 reintentos de 10s, C9 guardar credentials.json), función async rollback_cliente(slug, sudo_password, progress_callback). Cada paso envía step_start al inicio y step_done o step_error al terminar.", "archivo_destino": "pymesbot-installer/app/client_setup.py", "archivos_a_crear": [ "pymesbot-installer/app/client_setup.py" ], "contexto_spec": "Sección 8 completa de 02_PYMESBOT_INSTALLER_SPEC.md — todos los pasos C1 a C9, los comandos exactos, los timeouts, los mensajes de error específicos de certbot, y la función de rollback", "dependencias": [ "I2-T01", "I1-T02" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I2-T03", "proyecto": "pymesbot-installer", "sprint": 2, "prioridad": 3, "titulo": "Implementar installer.py — instalación de infraestructura base (Modo A)", "descripcion": "Crear app/installer.py con función async instalar_infraestructura(config, progress_callback) con los 5 pasos: A1 apt-get update (timeout 120s), A2 apt-get install nginx certbot python3-certbot-nginx (timeout 300s), A3 mkdir /opt/pymesbot (idempotente), A4 docker network create pymesbot_net (manejar error 'already exists' como éxito), A5 verificar nginx base config + systemctl enable + start. Cada paso con step_start/step_done/step_error y el hint apropiado.", "archivo_destino": "pymesbot-installer/app/installer.py", "archivos_a_crear": [ "pymesbot-installer/app/installer.py" ], "contexto_spec": "Sección 7 completa de 02_PYMESBOT_INSTALLER_SPEC.md — los 5 pasos A1 a A5 con comandos exactos, timeouts y mensajes de hint", "dependencias": [ "I1-T02", "I2-T01" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I2-T04", "proyecto": "pymesbot-installer", "sprint": 2, "prioridad": 4, "titulo": "Conectar el wizard con el backend real (reemplazar mocks)", "descripcion": "Actualizar wizard.js para conectar todos los pasos con las APIs reales: paso 0 llama GET /install/detect y renderiza las tarjetas con datos reales, paso 1 llama POST /install/validate-sudo, paso 3 llama POST /install/check-slug al perder el foco del slug, paso 4 llama POST /install/start al hacer click en Ejecutar, paso 5 conecta WebSocket real y maneja todos los eventos (step_start, output, step_done, step_error, done, fatal_error). Expandir/colapsar output del paso al hacer click en 'ver detalles'.", "archivo_destino": "pymesbot-installer/static/wizard.js", "archivos_a_crear": [], "contexto_spec": "Secciones 10 y 11 de 02_PYMESBOT_INSTALLER_SPEC.md — las APIs de cada paso y el manejo de eventos WebSocket en el paso 5", "dependencias": [ "I1-T05", "I1-T06", "I2-T02", "I2-T03" ], "status": "pending", "intentos": 0, "modelo_preferido": "minimax", "modelo_usado": null, "completada_el": null, "notas_error": null }, { "id": "I2-T05", "proyecto": "pymesbot-installer", "sprint": 2, "prioridad": 5, "titulo": "Crear docker-compose.yml del instalador (el que descarga el operador)", "descripcion": "Crear el docker-compose.yml raíz del instalador exactamente como está en la sección 5 del spec. Con los 4 volúmenes críticos: /var/run/docker.sock, /usr/bin/docker:ro, /opt/pymesbot, /etc/nginx. Puerto 80:8000. restart: 'no'. Crear también un README.md con instrucciones de uso de 4 pasos: curl -O, docker compose up -d, abrir URL con token, docker compose down.", "archivo_destino": "pymesbot-installer/", "archivos_a_crear": [ "pymesbot-installer/docker-compose.yml", "pymesbot-installer/README.md" ], "contexto_spec": "Secciones 2 y 5 de 02_PYMESBOT_INSTALLER_SPEC.md — el docker-compose.yml completo con todos los volúmenes y el README de uso", "dependencias": [ "I1-T01" ], "status": "pending", "intentos": 0, "modelo_preferido": "glm", "modelo_usado": null, "completada_el": null, "notas_error": null } ], "key_pool": [ { "id": "glm_1", "servicio": "glm", "api_base": "https://api.z.ai/api/paas/v4", "modelo": "glm-4.7", "key": "GLM_KEY_1", "ultimo_uso": null, "cooldown_segundos": 20, "disponible": true, "usos_hoy": 0 }, { "id": "minimax_1", "servicio": "minimax", "api_base": "https://api.minimax.io/v1", "modelo": "MiniMax-M2.5", "key": "MINIMAX_KEY_1", "ultimo_uso": "2026-02-17T16:52:06.200Z", "cooldown_segundos": 20, "disponible": true, "usos_hoy": 1 } ], "config": { "repo_backend": "https://gitea.cbcren.online/renato97/pymesbot-backend", "repo_installer": "https://gitea.cbcren.online/renato97/pymesbot-installer", "branch": "main", "commit_author_name": "PymesBot Bot", "commit_author_email": "bot@rvconsultas.com", "max_intentos_por_tarea": 3, "espera_entre_reintentos_segundos": 120, "loop_interval_segundos": 300, "spec_backend_path": "/repo/specs/01_PYMESBOT_PROJECT_SPEC.md", "spec_installer_path": "/repo/specs/02_PYMESBOT_INSTALLER_SPEC.md", "dominio_demo": "demo2.cbcren.online", "dominio_n8n": "n8n.cbcren.online" } }