diff --git a/tasks.json b/tasks.json new file mode 100644 index 0000000..22b3e42 --- /dev/null +++ b/tasks.json @@ -0,0 +1,722 @@ +{ + "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": 0, + "modelo_preferido": "minimax", + "modelo_usado": null, + "completada_el": null, + "notas_error": null + }, + { + "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": null, + "cooldown_segundos": 20, + "disponible": true, + "usos_hoy": 0 + } + ], + "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" + } +} \ No newline at end of file