# TEMPLATE: IMPLEMENTAR NUEVA FUNCIONALIDAD
# Fecha: _____________
# Funcionalidad: _____________
# Prioridad: [ ] Alta [ ] Media [ ] Baja
# Complejidad: [ ] Simple [ ] Media [ ] Compleja

## DESCRIPCIÓN DE LA FUNCIONALIDAD

### Objetivo:
_________________________________
_________________________________

### Problema que resuelve:
_________________________________
_________________________________

### Usuarios afectados:
- [ ] Agentes/Tarotistas
- [ ] Coordinadores
- [ ] Clientes llamantes
- [ ] Administradores
- [ ] Otro: _______________

### Comportamiento esperado:
_________________________________
_________________________________

## ANÁLISIS DE IMPACTO

### Componentes a modificar:
- [ ] Dialplan (extensions.conf)
- [ ] Scripts AGI Python
- [ ] Base de datos
- [ ] Panel web
- [ ] APIs
- [ ] WebSocket server
- [ ] Otro: _______________

### Riesgos identificados:
1. _______________
2. _______________
3. _______________

### Dependencias:
- [ ] Requiere nuevas tablas BD
- [ ] Requiere nuevos archivos de audio
- [ ] Requiere cambios en cliente web
- [ ] Requiere permisos especiales
- [ ] Otro: _______________

## DISEÑO TÉCNICO

### Arquitectura propuesta:
```
┌─────────────────┐
│                 │
│   Componente 1  │
│                 │
└────────┬────────┘
         │
         ▼
┌─────────────────┐
│                 │
│   Componente 2  │
│                 │
└─────────────────┘
```

### Flujo de datos:
1. _______________
2. _______________
3. _______________

### Pseudocódigo/Lógica principal:
```python
# Descripción general del algoritmo
def nueva_funcionalidad():
    # 1. Validar condiciones
    if not validar_prerequisitos():
        return error
    
    # 2. Ejecutar lógica principal
    resultado = procesar_funcionalidad()
    
    # 3. Registrar en BD/logs
    registrar_actividad(resultado)
    
    # 4. Retornar resultado
    return resultado
```

## IMPLEMENTACIÓN PASO A PASO

### PASO 1: PREPARACIÓN Y BACKUPS

```bash
# Ejecutado por: _______________ Fecha/Hora: _______________

# Backup completo del sistema
mysqldump -u asteriskuser -p asterisk > backup_asterisk_$(date +%Y%m%d_%H%M%S).sql
mysqldump -u asteriskuser -p panel_tarot > backup_panel_$(date +%Y%m%d_%H%M%S).sql

# Backup de código
tar -czf agi_backup_$(date +%Y%m%d_%H%M%S).tar.gz /var/lib/asterisk/agi-bin/
cp -r /var/www/html /var/www/html.backup_$(date +%Y%m%d_%H%M%S)

# Backup de configuración
tar -czf asterisk_config_backup_$(date +%Y%m%d_%H%M%S).tar.gz /etc/asterisk/
```

### PASO 2: CAMBIOS EN BASE DE DATOS (si aplica)

```sql
-- Crear nuevas tablas si necesario
CREATE TABLE IF NOT EXISTS _______________ (
    id INT AUTO_INCREMENT PRIMARY KEY,
    _______________ VARCHAR(___),
    _______________ INT,
    _______________ DATETIME,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_______________ (_______________)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Agregar columnas a tablas existentes
ALTER TABLE _______________ 
ADD COLUMN _______________ _______________ DEFAULT _______________ 
AFTER _______________;

-- Crear procedimientos almacenados si necesario
DELIMITER $$
CREATE PROCEDURE sp_______________ (
    IN p_______________ _______________
)
BEGIN
    -- Lógica del procedimiento
    _______________
END$$
DELIMITER ;
```

### PASO 3: CAMBIOS EN DIALPLAN (si aplica)

```asterisk
; En /etc/asterisk/extensions.conf

; Agregar nuevo contexto si necesario
[new-functionality-context]
exten => _______________,1,NoOp(=== NUEVA FUNCIONALIDAD: _______________ ===)
 same => n,Set(FUNCTION_START=${EPOCH})
 same => n,AGI(_______________,${EXTEN},${CALLERID(num)})
 same => n,NoOp(Resultado: ${FUNCTION_RESULT})
 same => n,GotoIf($["${FUNCTION_RESULT}" = "success"]?success,1:failed,1)

exten => success,1,Playback(_______________)
 same => n,Goto(${FUNCTION_RETURN_CONTEXT},${FUNCTION_RETURN_EXTEN},1)

exten => failed,1,Playback(error-message)
 same => n,Hangup()

; Modificar contextos existentes si necesario
[existing-context]
; Agregar opción en menú
exten => ___,1,Goto(new-functionality-context,_______________,1)
```

### PASO 4: IMPLEMENTAR LÓGICA EN PYTHON

#### Crear nuevo processor (si aplica)
```python
# /var/lib/asterisk/agi-bin/call_system/processors/new_functionality_processor.py

from .base_processor import BaseProcessor
import logging

class NewFunctionalityProcessor(BaseProcessor):
    """
    Procesador para _______________
    """
    
    def __init__(self, agi):
        super().__init__(agi)
        self.logger = logging.getLogger('NewFunctionality')
        
    def process(self, *args):
        """
        Procesa _______________
        
        Args:
            args[0]: _______________
            args[1]: _______________
        
        Returns:
            str: Resultado del procesamiento
        """
        try:
            self.log_processor_entry("NEW_FUNCTIONALITY", locals())
            
            # 1. Validar entrada
            if not self.validate_input(args):
                return self.handle_error("INVALID_INPUT")
            
            # 2. Obtener datos necesarios
            data = self.fetch_required_data()
            
            # 3. Ejecutar lógica principal
            result = self.execute_main_logic(data)
            
            # 4. Registrar resultado
            self.log_result(result)
            
            # 5. Configurar variables para dialplan
            self.set_dialplan_variables(result)
            
            return "success"
            
        except Exception as e:
            self.logger.error(f"Error en nueva funcionalidad: {str(e)}")
            return self.handle_error("PROCESSING_ERROR", str(e))
    
    def validate_input(self, args):
        """Valida parámetros de entrada"""
        # Implementar validaciones
        return True
    
    def fetch_required_data(self):
        """Obtiene datos necesarios de BD"""
        sql = """
        SELECT _______________
        FROM _______________
        WHERE _______________ = %s
        """
        return self.execute_db_query(sql, (_______________,))
    
    def execute_main_logic(self, data):
        """Ejecuta la lógica principal"""
        # Implementar lógica
        result = {
            'status': 'success',
            'data': _______________
        }
        return result
    
    def log_result(self, result):
        """Registra resultado en BD"""
        sql = """
        INSERT INTO _______________ 
        (_______________, _______________, _______________) 
        VALUES (%s, %s, %s)
        """
        self.execute_db_query(sql, (_______________,))
    
    def set_dialplan_variables(self, result):
        """Configura variables para el dialplan"""
        self.agi.set_variable("FUNCTION_RESULT", result['status'])
        self.agi.set_variable("FUNCTION_DATA", str(result['data']))
```

#### Modificar main_call_handler.py
```python
# Agregar import
from call_system.processors.new_functionality_processor import NewFunctionalityProcessor

# En la función main(), agregar caso:
elif processor_type == "new-functionality":
    processor = NewFunctionalityProcessor(agi)
    result = processor.process(*args)
```

### PASO 5: CAMBIOS EN PANEL WEB (si aplica)

#### Nuevo endpoint API
```php
// /var/www/html/api/new_functionality.php
<?php
require_once '../includes/auth.php';
require_once '../includes/db.php';

header('Content-Type: application/json');

// Verificar autenticación
if (!isAuthenticated()) {
    http_response_code(401);
    echo json_encode(['error' => 'No autorizado']);
    exit;
}

// Procesar request
$action = $_POST['action'] ?? $_GET['action'] ?? '';

switch ($action) {
    case 'get':
        // Obtener datos
        $sql = "SELECT * FROM _______________ WHERE _______________";
        $result = $conn->query($sql);
        $data = $result->fetch_all(MYSQLI_ASSOC);
        echo json_encode(['success' => true, 'data' => $data]);
        break;
        
    case 'update':
        // Actualizar datos
        $sql = "UPDATE _______________ SET _______________ = ? WHERE _______________ = ?";
        $stmt = $conn->prepare($sql);
        $stmt->bind_param('___', _______________);
        $stmt->execute();
        echo json_encode(['success' => true]);
        break;
        
    default:
        http_response_code(400);
        echo json_encode(['error' => 'Acción no válida']);
}
?>
```

#### Interfaz de usuario
```html
<!-- Agregar en panel apropiado -->
<div class="new-functionality-section">
    <h3>_______________</h3>
    <div class="controls">
        <button id="btn-_______________" class="btn btn-primary">
            _______________
        </button>
    </div>
    <div id="functionality-results"></div>
</div>

<script>
document.getElementById('btn-_______________').addEventListener('click', function() {
    fetch('/api/new_functionality.php?action=_______________')
        .then(response => response.json())
        .then(data => {
            if (data.success) {
                // Mostrar resultados
                document.getElementById('functionality-results').innerHTML = 
                    formatResults(data.data);
            }
        })
        .catch(error => console.error('Error:', error));
});
</script>
```

### PASO 6: ARCHIVOS DE AUDIO (si aplica)

```bash
# Preparar archivos de audio
cd /tmp

# Grabar o generar audios necesarios
# Opción 1: Usar TTS
echo "_______________ " | text2wave -o _______________.wav

# Opción 2: Convertir desde MP3
sox _______________.mp3 -r 8000 -c 1 _______________.wav

# Mover a directorio de Asterisk
mv _______________.wav /var/lib/asterisk/sounds/es/
chown asterisk:asterisk /var/lib/asterisk/sounds/es/_______________.wav
chmod 644 /var/lib/asterisk/sounds/es/_______________.wav

# Verificar
asterisk -rx "core show sound _______________"
```

## PRUEBAS

### PRUEBAS UNITARIAS

```python
# /tests/test_new_functionality.py
import unittest
from mock import Mock, patch

class TestNewFunctionality(unittest.TestCase):
    
    def setUp(self):
        self.agi_mock = Mock()
        self.processor = NewFunctionalityProcessor(self.agi_mock)
    
    def test_validate_input_valid(self):
        """Prueba validación con entrada válida"""
        result = self.processor.validate_input(['param1', 'param2'])
        self.assertTrue(result)
    
    def test_validate_input_invalid(self):
        """Prueba validación con entrada inválida"""
        result = self.processor.validate_input([])
        self.assertFalse(result)
    
    @patch('processor.execute_db_query')
    def test_fetch_data(self, mock_db):
        """Prueba obtención de datos"""
        mock_db.return_value = [{'id': 1, 'data': 'test'}]
        result = self.processor.fetch_required_data()
        self.assertEqual(len(result), 1)

# Ejecutar pruebas
if __name__ == '__main__':
    unittest.main()
```

### PRUEBAS DE INTEGRACIÓN

```bash
# Script de prueba integral
cat > /tmp/test_new_functionality.sh << 'EOF'
#!/bin/bash

echo "=== PRUEBA DE NUEVA FUNCIONALIDAD ==="
echo "Fecha: $(date)"

# 1. Verificar BD
echo -e "\n1. Verificando base de datos..."
mysql -u asteriskuser -p asterisk -e "SELECT COUNT(*) FROM _______________"

# 2. Probar AGI directamente
echo -e "\n2. Probando AGI..."
cd /var/lib/asterisk/agi-bin
echo -e "agi_request: test.agi\nagi_channel: TEST/test\nagi_callerid: 123456789\n\n" | \
    python3 main_call_handler.py new-functionality test_param

# 3. Probar desde Asterisk
echo -e "\n3. Probando desde Asterisk..."
asterisk -rx "originate Local/s@new-functionality-context application Playback demo-congrats"

# 4. Verificar logs
echo -e "\n4. Verificando logs..."
tail -n 20 /var/log/asterisk/python_call_system.log | grep "NEW_FUNCTIONALITY"

echo -e "\n=== FIN DE PRUEBAS ==="
EOF

chmod +x /tmp/test_new_functionality.sh
/tmp/test_new_functionality.sh
```

### PRUEBAS DE USUARIO

#### Escenario 1: Uso normal
1. [ ] Usuario accede a funcionalidad
2. [ ] Sistema responde correctamente
3. [ ] Datos se guardan en BD
4. [ ] Usuario recibe confirmación

#### Escenario 2: Casos límite
1. [ ] Sin datos de entrada
2. [ ] Datos inválidos
3. [ ] Usuario sin permisos
4. [ ] Sistema bajo carga

#### Escenario 3: Errores
1. [ ] BD no disponible
2. [ ] Timeout en procesamiento
3. [ ] Error en audio
4. [ ] Conflicto con otra llamada

## DEPLOYMENT

### DESARROLLO
```bash
# 1. Deploy código
rsync -av /local/path/ user@dev-server:/var/lib/asterisk/agi-bin/

# 2. Aplicar cambios BD
mysql -h dev-server -u asteriskuser -p asterisk < changes.sql

# 3. Reload Asterisk
ssh user@dev-server "asterisk -rx 'dialplan reload'"

# 4. Ejecutar pruebas
ssh user@dev-server "/tmp/test_new_functionality.sh"
```

### STAGING
```bash
# Repetir proceso con mayor cuidado
# Incluir pruebas de carga si necesario
```

### PRODUCCIÓN
```bash
# 1. Ventana de mantenimiento
echo "MANTENIMIENTO: $(date) - Implementando _______________" >> /var/log/maintenance.log

# 2. Deploy con mínimo downtime
# - Preparar todos los archivos
# - Aplicar cambios BD en transacción
# - Deploy código
# - Reload servicios

# 3. Verificación inmediata
# - Prueba funcional básica
# - Monitoreo de errores
# - Rollback si necesario
```

## MONITOREO POST-IMPLEMENTACIÓN

### Métricas a observar:
```sql
-- Crear tabla de métricas si no existe
CREATE TABLE IF NOT EXISTS functionality_metrics (
    id INT AUTO_INCREMENT PRIMARY KEY,
    timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
    metric_name VARCHAR(100),
    metric_value DECIMAL(10,2),
    details JSON,
    INDEX idx_timestamp_metric (timestamp, metric_name)
);

-- Query de monitoreo
SELECT 
    DATE_FORMAT(timestamp, '%Y-%m-%d %H:00') as hora,
    metric_name,
    COUNT(*) as total_uses,
    AVG(metric_value) as avg_value,
    MAX(metric_value) as max_value
FROM functionality_metrics
WHERE timestamp > NOW() - INTERVAL 24 HOUR
GROUP BY hora, metric_name
ORDER BY hora DESC;
```

### Dashboard de monitoreo:
```bash
# Script de monitoreo continuo
cat > /tmp/monitor_functionality.sh << 'EOF'
#!/bin/bash
while true; do
    clear
    echo "=== MONITOR NUEVA FUNCIONALIDAD - $(date) ==="
    
    # Uso en última hora
    echo -e "\nUso última hora:"
    mysql -u asteriskuser -p[PASS] asterisk -e "
        SELECT COUNT(*) as uses_last_hour 
        FROM _______________ 
        WHERE created_at > NOW() - INTERVAL 1 HOUR"
    
    # Errores
    echo -e "\nErrores últimos 10 min:"
    grep "ERROR.*NEW_FUNCTIONALITY" /var/log/asterisk/python_call_system.log | \
        grep "$(date +%Y-%m-%d)" | tail -5
    
    # Performance
    echo -e "\nPerformance:"
    mysql -u asteriskuser -p[PASS] asterisk -e "
        SELECT AVG(processing_time) as avg_time,
               MAX(processing_time) as max_time
        FROM functionality_metrics
        WHERE timestamp > NOW() - INTERVAL 10 MINUTE"
    
    sleep 30
done
EOF

chmod +x /tmp/monitor_functionality.sh
```

## DOCUMENTACIÓN

### Actualizar documentación técnica:
1. **README de la funcionalidad**
```markdown
# Nueva Funcionalidad: _______________

## Descripción
_______________

## Cómo usar
1. _______________
2. _______________

## Configuración
- Parámetro 1: _______________
- Parámetro 2: _______________

## Troubleshooting
- Si error X: _______________
- Si error Y: _______________
```

2. **Actualizar docs existentes**
- [ ] DIALPLAN_COMPLETO.md (si modificó dialplan)
- [ ] AGI_DETALLADO.md (si agregó AGI)
- [ ] MODELO_DATOS_EXPLICADO.md (si modificó BD)
- [ ] FLUJOS_LLAMADA.md (si agregó flujo)

### Manual de usuario:
```markdown
# Manual de Usuario - _______________

## ¿Qué es?
_______________

## ¿Cómo acceder?
1. _______________
2. _______________

## Ejemplos de uso
### Ejemplo 1: _______________
- Paso 1: _______________
- Paso 2: _______________
- Resultado: _______________

## Preguntas frecuentes
**P: _______________**
R: _______________
```

## ROLLBACK

### Plan de rollback:
```bash
#!/bin/bash
# rollback_functionality.sh

echo "=== INICIANDO ROLLBACK - $(date) ==="

# 1. Detener servicios afectados
echo "1. Deteniendo servicios..."
# systemctl stop ...

# 2. Restaurar BD
echo "2. Restaurando base de datos..."
mysql -u asteriskuser -p asterisk < backup_asterisk_[FECHA].sql

# 3. Restaurar código
echo "3. Restaurando código..."
rm -rf /var/lib/asterisk/agi-bin
tar -xzf agi_backup_[FECHA].tar.gz -C /

# 4. Restaurar configuración
echo "4. Restaurando configuración..."
rm -rf /etc/asterisk
tar -xzf asterisk_config_backup_[FECHA].tar.gz -C /

# 5. Reiniciar servicios
echo "5. Reiniciando servicios..."
systemctl restart asterisk

# 6. Verificar
echo "6. Verificando..."
asterisk -rx "core show channels"

echo "=== ROLLBACK COMPLETADO - $(date) ==="
```

## LECCIONES APRENDIDAS

### ¿Qué salió bien?
_________________________________
_________________________________

### ¿Qué problemas surgieron?
_________________________________
_________________________________

### ¿Qué mejoraríamos?
_________________________________
_________________________________

## CHECKLIST FINAL

### Pre-implementación:
- [ ] Backups realizados
- [ ] Pruebas en desarrollo exitosas
- [ ] Documentación preparada
- [ ] Plan de rollback listo
- [ ] Usuarios informados

### Post-implementación:
- [ ] Funcionalidad operativa
- [ ] Sin errores críticos en logs
- [ ] Métricas normales
- [ ] Usuarios pueden acceder
- [ ] Documentación actualizada

### Seguimiento (1 semana):
- [ ] Análisis de uso
- [ ] Feedback de usuarios
- [ ] Ajustes menores aplicados
- [ ] Documentación finalizada
- [ ] Cierre formal del cambio

## NOTAS/OBSERVACIONES

_________________________________
_________________________________
_________________________________

## FIRMAS

Solicitado por: _______________ Fecha: _______________
Diseñado por: _______________ Fecha: _______________
Desarrollado por: _______________ Fecha: _______________
Probado por: _______________ Fecha: _______________
Implementado por: _______________ Fecha: _______________
Aprobado por: _______________ Fecha: _______________