Funcionalidade Laravel Telegram Bot

📋 Visão Geral

Guia completo para implementação do sistema de Telegram Webhook em Laravel, baseado no projeto Rei do Óleo. Este sistema inclui processamento de mensagens, validação de webhooks, tratamento de erros e sistema de comandos unificado.

🚀 Comando de Implementação

implementar telegram webhook laravel completo

⚙️ Pré-requisitos

Antes de implementar, certifique-se de ter:

  • Laravel 12 instalado
  • PHP 8.2+ configurado
  • Composer para dependências
  • Redis para cache (recomendado)
  • Bot Token do Telegram configurado
  • Webhook URL configurada

📁 Estrutura de Arquivos

O sistema será implementado com a seguinte estrutura:

app/
├── Http/
│   ├── Controllers/Api/
│   │   ├── TelegramWebhookController.php
│   │   └── TelegramStatsController.php
│   ├── Middleware/
│   │   ├── TelegramWebhookSecretMiddleware.php
│   │   ├── TelegramWebhookExceptionHandler.php
│   │   └── TelegramWebhookLoggingMiddleware.php
│   ├── Requests/
│   │   ├── TelegramWebhookRequest.php
│   │   └── TelegramWebhookSetupRequest.php
│   └── Resources/
│       └── TelegramWebhookResource.php
├── Services/
│   ├── TelegramWebhookService.php
│   ├── TelegramBotService.php
│   ├── TelegramMessageProcessorService.php
│   └── Telegram/
│       ├── TelegramWebhookValidationService.php
│       └── TelegramMessageProcessorService.php
└── Console/Commands/
    └── TestTelegramWebhook.php

🔧 Passo a Passo de Implementação

Passo 1: Configuração Inicial

1. Configurar variáveis de ambiente (.env):

TELEGRAM_ENABLED=true
TELEGRAM_BOT_TOKEN=seu_bot_token_aqui
TELEGRAM_WEBHOOK_SECRET=seu_secret_aqui
TELEGRAM_RECIPIENTS=123456789,987654321

2. Configurar services.php:

'telegram' => [
    'enabled' => env('TELEGRAM_ENABLED', false),
    'bot_token' => env('TELEGRAM_BOT_TOKEN'),
    'webhook_secret' => env('TELEGRAM_WEBHOOK_SECRET', ''),
    'recipients' => explode(',', env('TELEGRAM_RECIPIENTS', '')),
],

Passo 2: Implementar Classes Core

Próximos passos serão adicionados gradualmente…

📋 Checklist de Implementação

Antes de Começar

  • [ ] Laravel 12 instalado
  • [ ] PHP 8.2+ configurado
  • [ ] Redis configurado
  • [ ] Bot Token do Telegram obtido
  • [ ] Webhook URL configurada

Durante a Implementação

  • [ ] Configurar variáveis de ambiente
  • [ ] Implementar Controllers
  • [ ] Implementar Services
  • [ ] Implementar Middlewares
  • [ ] Implementar Requests
  • [ ] Implementar Resources
  • [ ] Configurar rotas
  • [ ] Implementar testes

Após a Implementação

  • [ ] Testar webhook
  • [ ] Validar processamento de mensagens
  • [ ] Verificar logs
  • [ ] Testar comandos

🔍 Troubleshooting

Problemas Comuns

1. Webhook não recebe mensagens:

  • Verificar se a URL está correta
  • Verificar se o bot token está válido
  • Verificar logs do Laravel

2. Erro de validação:

  • Verificar estrutura do payload
  • Verificar regras de validação
  • Verificar logs de erro

3. Comandos não funcionam:

  • Verificar sistema de comandos
  • Verificar autorização do usuário
  • Verificar logs de processamento

📝 Próximas Seções

As próximas seções serão adicionadas gradualmente:

  • Seção 1: Controllers e Rotas
  • Seção 2: Services e Processamento
  • Seção 3: Middlewares e Validação
  • Seção 4: Requests e Resources
  • Seção 5: Testes e Comandos
  • Seção 6: Scripts de Instalação

📝 Seção 0: Dependências Essenciais

LoggingServiceInterface.php

<?php
 
namespace App\Contracts;
 
use Illuminate\Http\Request;
 
interface LoggingServiceInterface
{
    /**
     * Log API requests and responses
     */
    public function logApiRequest(Request $request, array $context = []): void;
 
    /**
     * Log API responses
     */
    public function logApiResponse(int $statusCode, array $response, float $duration, array $context = []): void;
 
    /**
     * Log business operations
     */
    public function logBusinessOperation(string $operation, array $data, string $status = 'success', array $context = []): void;
 
    /**
     * Log security events
     */
    public function logSecurityEvent(string $event, array $data, string $level = 'warning', array $context = []): void;
 
    /**
     * Log performance metrics
     */
    public function logPerformance(string $operation, float $duration, array $metrics = [], array $context = []): void;
 
    /**
     * Log audit trail
     */
    public function logAudit(string $action, string $model, int $modelId, array $changes = [], array $context = []): void;
 
    /**
     * Log Telegram bot events
     */
    public function logTelegramEvent(string $event, array $data, string $level = 'info', array $context = []): void;
 
    /**
     * Log WhatsApp events
     */
    public function logWhatsAppEvent(string $event, array $data, string $level = 'info', array $context = []): void;
 
    /**
     * Log exceptions with context
     */
    public function logException(\Throwable $exception, array $context = []): void;
 
    /**
     * Get log statistics
     */
    public function getLogStats(): array;
}

LoggingService.php

<?php
 
namespace App\Services;
 
use App\Contracts\LoggingServiceInterface;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;
use Illuminate\Http\Request;
use Spatie\Activitylog\ActivityLogger;
 
class LoggingService implements LoggingServiceInterface
{
    /**
     * Log API requests and responses
     */
    public function logApiRequest(Request $request, array $context = []): void
    {
        $logData = array_merge([
            'request_id' => uniqid('api_', true),
            'method' => $request->method(),
            'url' => $request->fullUrl(),
            'ip' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'user_id' => $request->user()?->id,
            'headers' => $this->sanitizeHeaders($request->headers->all()),
            'timestamp' => now()->toISOString(),
        ], $context);
 
        if ($request->method() !== 'GET') {
            $logData['body'] = $this->sanitizeBody($request->all());
        }
 
        Log::channel('api')->info('API Request', $logData);
    }
 
    /**
     * Log API responses
     */
    public function logApiResponse(int $statusCode, array $response, float $duration, array $context = []): void
    {
        $logData = array_merge([
            'status_code' => $statusCode,
            'duration_ms' => round($duration, 2),
            'response_size' => strlen(json_encode($response)),
            'timestamp' => now()->toISOString(),
        ], $context);
 
        if ($statusCode >= 400) {
            $logData['error_response'] = $response;
            Log::channel('api')->error('API Error Response', $logData);
        } else {
            Log::channel('api')->info('API Response', $logData);
        }
    }
 
    /**
     * Log business operations
     */
    public function logBusinessOperation(string $operation, array $data, string $status = 'success', array $context = []): void
    {
        $logData = array_merge([
            'operation' => $operation,
            'status' => $status,
            'user_id' => Auth::id(),
            'timestamp' => now()->toISOString(),
        ], $data, $context);
 
        Log::channel('business')->info('Business Operation', $logData);
    }
 
    /**
     * Log security events
     */
    public function logSecurityEvent(string $event, array $data, string $level = 'warning', array $context = []): void
    {
        $logData = array_merge([
            'event' => $event,
            'level' => $level,
            'user_id' => Auth::id(),
            'ip' => request()->ip(),
            'user_agent' => request()->userAgent(),
            'timestamp' => now()->toISOString(),
        ], $data, $context);
 
        Log::channel('security')->$level('Security Event', $logData);
    }
 
    /**
     * Log performance metrics
     */
    public function logPerformance(string $operation, float $duration, array $metrics = [], array $context = []): void
    {
        $logData = array_merge([
            'operation' => $operation,
            'duration_ms' => round($duration, 2),
            'memory_usage' => memory_get_usage(true),
            'memory_peak' => memory_get_peak_usage(true),
            'timestamp' => now()->toISOString(),
        ], $metrics, $context);
 
        Log::channel('performance')->info('Performance Metric', $logData);
    }
 
    /**
     * Log audit trail
     */
    public function logAudit(string $action, string $model, int $modelId, array $changes = [], array $context = []): void
    {
        $logData = array_merge([
            'action' => $action,
            'model' => $model,
            'model_id' => $modelId,
            'changes' => $changes,
            'user_id' => Auth::id(),
            'timestamp' => now()->toISOString(),
        ], $context);
 
        Log::channel('audit')->info('Audit Trail', $logData);
    }
 
    /**
     * Log Telegram bot events
     */
    public function logTelegramEvent(string $event, array $data, string $level = 'info', array $context = []): void
    {
        $logData = array_merge([
            'event' => $event,
            'level' => $level,
            'timestamp' => now()->toISOString(),
        ], $data, $context);
 
        Log::channel('telegram')->$level('Telegram Event', $logData);
    }
 
    /**
     * Log WhatsApp events
     */
    public function logWhatsAppEvent(string $event, array $data, string $level = 'info', array $context = []): void
    {
        $logData = array_merge([
            'event' => $event,
            'level' => $level,
            'timestamp' => now()->toISOString(),
        ], $data, $context);
 
        Log::channel('whatsapp')->$level('WhatsApp Event', $logData);
    }
 
    /**
     * Log exceptions with context
     */
    public function logException(\Throwable $exception, array $context = []): void
    {
        $logData = array_merge([
            'exception' => get_class($exception),
            'message' => $exception->getMessage(),
            'file' => $exception->getFile(),
            'line' => $exception->getLine(),
            'trace' => $exception->getTraceAsString(),
            'user_id' => Auth::id(),
            'timestamp' => now()->toISOString(),
        ], $context);
 
        Log::channel('errors')->error('Exception', $logData);
    }
 
    /**
     * Get log statistics
     */
    public function getLogStats(): array
    {
        return [
            'channels' => ['api', 'business', 'security', 'performance', 'audit', 'telegram', 'whatsapp', 'errors'],
            'timestamp' => now()->toISOString(),
        ];
    }
 
    /**
     * Sanitize headers for logging
     */
    private function sanitizeHeaders(array $headers): array
    {
        $sensitiveHeaders = ['authorization', 'cookie', 'x-api-key', 'x-csrf-token'];
 
        foreach ($sensitiveHeaders as $header) {
            if (isset($headers[$header])) {
                $headers[$header] = ['***REDACTED***'];
            }
        }
 
        return $headers;
    }
 
    /**
     * Sanitize request body for logging
     */
    private function sanitizeBody(array $body): array
    {
        $sensitiveFields = ['password', 'token', 'secret', 'key', 'api_key'];
 
        foreach ($sensitiveFields as $field) {
            if (isset($body[$field])) {
                $body[$field] = '***REDACTED***';
            }
        }
 
        return $body;
    }
}

MessageFlowTrackerInterface.php

<?php
 
namespace App\Contracts;
 
interface MessageFlowTrackerInterface
{
    // Core tracking methods
    public function trackMethod(string $className, string $methodName, array $inputData = [], array $outputData = []): void;
    public function endMethod(string $className, string $methodName, array $outputData = []): void;
 
    // Report generation
    public function generateFlowReport(array $payload): string;
    public function generateUserReport(array $payload): string;
 
    // Pipeline control
    public function startTracking(string $messageId): void;
    public function endTracking(): void;
    public function clearTrace(): void;
 
    // Data retrieval
    public function getExecutedMethods(): array;
    public function getExpectedMethods(): array;
    public function getMethodData(): array;
 
    // Utility methods
    public function identifyMessageType(array $payload): string;
    public function saveTrace(): void;
    public function isEnabled(): bool;
}

MessageFlowTrackerService.php

<?php
 
namespace App\Services;
 
use App\Contracts\MessageFlowTrackerInterface;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Cache;
 
class MessageFlowTrackerService implements MessageFlowTrackerInterface
{
    private array $executedMethods = [];
    private array $expectedMethods = [];
    private array $methodData = [];
    private array $timestamps = [];
    private string $messageId;
    private bool $isEnabled;
 
    public function __construct()
    {
        $this->isEnabled = config('message-flow.enabled', false);
        $this->messageId = uniqid('msg_', true);
 
        // Define o fluxo esperado para cada tipo de mensagem
        $this->expectedMethods = [
            'text' => [
                'TelegramMessageProcessorService.processWebhookPayload',
                'TelegramMessageProcessorService.processTextMessage',
                'TelegramBotService.processMessage',
                'TelegramChannel.sendMessageWithKeyboard'
            ],
            'voice' => [
                'TelegramMessageProcessorService.processWebhookPayload',
                'TelegramMessageProcessorService.processVoiceMessage',
                'SpeechToTextService.convertVoiceToText',
                'TelegramBotService.processMessage',
                'TelegramChannel.sendMessageWithKeyboard'
            ],
            'callback_query' => [
                'TelegramMessageProcessorService.processWebhookPayload',
                'TelegramMessageProcessorService.processCallbackQuery',
                'TelegramBotService.processCallbackQuery',
                'TelegramChannel.sendTextMessage'
            ]
        ];
    }
 
    /**
     * Track method execution
     */
    public function trackMethod(string $className, string $methodName, array $inputData = [], array $outputData = []): void
    {
        if (!$this->isEnabled) {
            return;
        }
 
        $methodKey = "{$className}.{$methodName}";
        $this->executedMethods[] = $methodKey;
        $this->timestamps[$methodKey] = microtime(true);
        $this->methodData[$methodKey] = [
            'input' => $inputData,
            'output' => $outputData,
            'timestamp' => now()->toISOString()
        ];
    }
 
    /**
     * End method tracking
     */
    public function endMethod(string $className, string $methodName, array $outputData = []): void
    {
        if (!$this->isEnabled) {
            return;
        }
 
        $methodKey = "{$className}.{$methodName}";
 
        if (isset($this->methodData[$methodKey])) {
            $this->methodData[$methodKey]['output'] = $outputData;
            $this->methodData[$methodKey]['duration'] = microtime(true) - $this->timestamps[$methodKey];
        }
    }
 
    /**
     * Generate flow report
     */
    public function generateFlowReport(array $payload): string
    {
        if (!$this->isEnabled) {
            return 'Message flow tracking is disabled';
        }
 
        $messageType = $this->identifyMessageType($payload);
        $expected = $this->expectedMethods[$messageType] ?? [];
        $missing = array_diff($expected, $this->executedMethods);
        $extra = array_diff($this->executedMethods, $expected);
 
        $report = "=== MESSAGE FLOW REPORT ===\n";
        $report .= "Message Type: {$messageType}\n";
        $report .= "Message ID: {$this->messageId}\n";
        $report .= "Executed Methods: " . count($this->executedMethods) . "\n";
        $report .= "Expected Methods: " . count($expected) . "\n";
        $report .= "Missing Methods: " . count($missing) . "\n";
        $report .= "Extra Methods: " . count($extra) . "\n\n";
 
        if (!empty($missing)) {
            $report .= "MISSING METHODS:\n";
            foreach ($missing as $method) {
                $report .= "  - {$method}\n";
            }
            $report .= "\n";
        }
 
        if (!empty($extra)) {
            $report .= "EXTRA METHODS:\n";
            foreach ($extra as $method) {
                $report .= "  - {$method}\n";
            }
            $report .= "\n";
        }
 
        return $report;
    }
 
    /**
     * Generate user-friendly report
     */
    public function generateUserReport(array $payload): string
    {
        if (!$this->isEnabled) {
            return 'Tracking disabled';
        }
 
        $messageType = $this->identifyMessageType($payload);
        $expected = $this->expectedMethods[$messageType] ?? [];
        $missing = array_diff($expected, $this->executedMethods);
 
        if (empty($missing)) {
            return "✅ Message processed successfully through all expected steps";
        }
 
        $report = "⚠️ Message processing incomplete:\n";
        $report .= "Missing steps: " . count($missing) . "\n";
 
        foreach ($missing as $method) {
            $report .= "• " . str_replace('.', ' → ', $method) . "\n";
        }
 
        return $report;
    }
 
    /**
     * Start tracking
     */
    public function startTracking(string $messageId): void
    {
        $this->messageId = $messageId;
        $this->clearTrace();
    }
 
    /**
     * End tracking
     */
    public function endTracking(): void
    {
        if ($this->isEnabled) {
            $this->saveTrace();
        }
    }
 
    /**
     * Clear trace
     */
    public function clearTrace(): void
    {
        $this->executedMethods = [];
        $this->methodData = [];
        $this->timestamps = [];
    }
 
    /**
     * Get executed methods
     */
    public function getExecutedMethods(): array
    {
        return $this->executedMethods;
    }
 
    /**
     * Get expected methods
     */
    public function getExpectedMethods(): array
    {
        return $this->expectedMethods;
    }
 
    /**
     * Get method data
     */
    public function getMethodData(): array
    {
        return $this->methodData;
    }
 
    /**
     * Identify message type
     */
    public function identifyMessageType(array $payload): string
    {
        if (isset($payload['callback_query'])) {
            return 'callback_query';
        }
 
        if (isset($payload['message'])) {
            $message = $payload['message'];
 
            if (isset($message['text'])) {
                return 'text';
            }
            if (isset($message['voice'])) {
                return 'voice';
            }
            if (isset($message['audio'])) {
                return 'audio';
            }
        }
 
        return 'unknown';
    }
 
    /**
     * Save trace to cache
     */
    public function saveTrace(): void
    {
        if (!$this->isEnabled) {
            return;
        }
 
        try {
            $traceData = [
                'message_id' => $this->messageId,
                'executed_methods' => $this->executedMethods,
                'method_data' => $this->methodData,
                'timestamp' => now()->toISOString()
            ];
 
            Cache::put("message_trace_{$this->messageId}", $traceData, 60); // 1 hour
        } catch (\Exception $e) {
            Log::error('Failed to save message trace', [
                'error' => $e->getMessage(),
                'message_id' => $this->messageId
            ]);
        }
    }
 
    /**
     * Check if tracking is enabled
     */
    public function isEnabled(): bool
    {
        return $this->isEnabled;
    }
}

NotificationChannelInterface.php

<?php
 
namespace App\Contracts;
 
interface NotificationChannelInterface
{
    /**
     * Send text message
     *
     * @param string $message
     * @param string|null $recipient
     * @return array
     */
    public function sendTextMessage(string $message, ?string $recipient = null): array;
 
    /**
     * Send notification with data
     *
     * @param array $data
     * @return array
     */
    public function sendNotification(array $data): array;
 
    /**
     * Test connection
     *
     * @return array
     */
    public function testConnection(): array;
 
    /**
     * Get channel name
     *
     * @return string
     */
    public function getChannelName(): string;
 
    /**
     * Check if channel is enabled
     *
     * @return bool
     */
    public function isEnabled(): bool;
}

MessageTrackingInterface.php

<?php
 
namespace App\Contracts;
 
/**
 * Interface para métodos de tracking de mensagens
 * Esta interface define os métodos que devem estar disponíveis
 * para qualquer classe que precise rastrear execução de métodos
 */
interface MessageTrackingInterface
{
    /**
     * Inicia o tracking de um método
     */
    public function trackMethod(string $methodName, array $inputData = [], array $outputData = []): void;
 
    /**
     * Finaliza o tracking de um método
     */
    public function endMethod(string $methodName, array $outputData = []): void;
 
    /**
     * Inicializa o sistema de tracking
     */
    public function initializeTracking(): void;
}

Service Providers

<?php
// app/Providers/LoggingServiceProvider.php
 
namespace App\Providers;
 
use Illuminate\Support\ServiceProvider;
use App\Contracts\LoggingServiceInterface;
use App\Services\LoggingService;
 
class LoggingServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->bind(LoggingServiceInterface::class, LoggingService::class);
    }
 
    public function boot(): void
    {
        // Publish configuration if needed
    }
}
<?php
// app/Providers/MessageFlowServiceProvider.php
 
namespace App\Providers;
 
use App\Contracts\MessageFlowTrackerInterface;
use App\Services\MessageFlowTrackerService;
use Illuminate\Support\ServiceProvider;
 
class MessageFlowServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(MessageFlowTrackerInterface::class, MessageFlowTrackerService::class);
    }
 
    public function boot(): void
    {
        // Publish configuration if needed
    }
}

Configuração (config/app.php)

// Adicionar no array 'providers' do config/app.php
 
'providers' => [
    // ... outros providers
    App\Providers\LoggingServiceProvider::class,
    App\Providers\MessageFlowServiceProvider::class,
    // ... outros providers
],

Configuração (config/services.php)

<?php
 
return [
    // ... outras configurações
 
    'telegram' => [
        'enabled' => env('TELEGRAM_ENABLED', false),
        'bot_token' => env('TELEGRAM_BOT_TOKEN'),
        'webhook_secret' => env('TELEGRAM_WEBHOOK_SECRET', ''),
        'recipients' => array_filter(explode(',', env('TELEGRAM_RECIPIENTS', ''))),
    ],
 
    // ... outras configurações
];

Configuração (.env)

# ============================================================================
# TELEGRAM BOT CONFIGURATION
# ============================================================================
 
# Enable/Disable Telegram Bot
TELEGRAM_ENABLED=true
 
# Bot Token from @BotFather
TELEGRAM_BOT_TOKEN=your_bot_token_here
 
# Webhook Secret for Security (optional but recommended)
TELEGRAM_WEBHOOK_SECRET=your_webhook_secret_here
 
# Recipients (Chat IDs separated by commas)
TELEGRAM_RECIPIENTS=123456789,987654321
 
# ============================================================================
# MESSAGE FLOW TRACKING CONFIGURATION
# ============================================================================
 
# Enable/Disable Message Flow Tracking
MESSAGE_FLOW_TRACKING_ENABLED=true
 
# Output Configuration
MESSAGE_FLOW_SEND_TO_USER=true
MESSAGE_FLOW_LOG_TO_FILE=true
MESSAGE_FLOW_CACHE_TRACES=true
 
# Performance Thresholds (milliseconds)
MESSAGE_FLOW_SLOW_THRESHOLD=100
MESSAGE_FLOW_VERY_SLOW_THRESHOLD=500
 
# Memory Thresholds (MB)
MESSAGE_FLOW_MEMORY_WARNING=50
MESSAGE_FLOW_MEMORY_CRITICAL=100
 
# Storage TTL (minutes)
MESSAGE_FLOW_CACHE_TTL=1440
MESSAGE_FLOW_DB_TTL=10080

Configuração de Logging (config/logging.php)

<?php
 
return [
    // ... outras configurações
 
    'channels' => [
        // ... outros canais
 
        'api' => [
            'driver' => 'daily',
            'path' => storage_path('logs/api.log'),
            'level' => 'info',
            'days' => 30,
        ],
 
        'business' => [
            'driver' => 'daily',
            'path' => storage_path('logs/business.log'),
            'level' => 'info',
            'days' => 90,
        ],
 
        'security' => [
            'driver' => 'daily',
            'path' => storage_path('logs/security.log'),
            'level' => 'warning',
            'days' => 365,
        ],
 
        'performance' => [
            'driver' => 'daily',
            'path' => storage_path('logs/performance.log'),
            'level' => 'info',
            'days' => 30,
        ],
 
        'audit' => [
            'driver' => 'daily',
            'path' => storage_path('logs/audit.log'),
            'level' => 'info',
            'days' => 365,
        ],
 
        'telegram' => [
            'driver' => 'daily',
            'path' => storage_path('logs/telegram.log'),
            'level' => 'info',
            'days' => 30,
        ],
 
        'whatsapp' => [
            'driver' => 'daily',
            'path' => storage_path('logs/whatsapp.log'),
            'level' => 'info',
            'days' => 30,
        ],
 
        'errors' => [
            'driver' => 'daily',
            'path' => storage_path('logs/errors.log'),
            'level' => 'error',
            'days' => 30,
        ],
    ],
];

TelegramMessageProcessorService.php

<?php
 
namespace App\Services;
 
use App\Contracts\LoggingServiceInterface;
use App\Contracts\MessageFlowTrackerInterface;
use App\Contracts\MessageTrackingInterface;
use App\Services\Channels\TelegramChannel;
 
class TelegramMessageProcessorService implements MessageTrackingInterface
{
    public function __construct(
        private TelegramBotService $telegramBotService,
        private TelegramChannel $telegramChannel,
        private LoggingServiceInterface $loggingService,
        private MessageFlowTrackerInterface $flowTracker,
        private ?SpeechToTextService $speechService = null
    ) {
        $this->initializeTracking();
    }
 
    /**
     * Process webhook payload
     */
    public function processWebhookPayload(array $payload): array
    {
        // Inicia tracking
        $this->trackMethod('processWebhookPayload', ['payload' => $payload]);
 
        try {
            // Check if it's a callback query (button click)
            if (isset($payload['callback_query'])) {
                $result = $this->processCallbackQuery($payload['callback_query']);
                $this->endMethod('processWebhookPayload', ['result' => $result]);
                return $result;
            }
 
            // Verify if it's a message
            if (!isset($payload['message'])) {
                $result = [
                    'success' => false,
                    'status' => 'ignored',
                    'message' => 'No message in payload'
                ];
 
                $this->endMethod('processWebhookPayload', ['result' => $result]);
                return $result;
            }
 
            $message = $payload['message'];
 
            // Process different message types
            if (isset($message['text'])) {
                $result = $this->processTextMessage($message);
                $this->endMethod('processWebhookPayload', ['result' => $result]);
                return $result;
            }
 
            if (isset($message['voice'])) {
                $result = $this->processVoiceMessage($message);
                $this->endMethod('processWebhookPayload', ['result' => $result]);
                return $result;
            }
 
            if (isset($message['audio'])) {
                $result = $this->processAudioMessage($message);
                $this->endMethod('processWebhookPayload', ['result' => $result]);
                return $result;
            }
 
            $result = $this->createIgnoredResult('Unsupported message type');
            $this->endMethod('processWebhookPayload', ['result' => $result]);
            return $result;
 
        } catch (\Exception $e) {
            $result = [
                'success' => false,
                'status' => 'error',
                'message' => 'Internal server error',
                'error' => $e->getMessage()
            ];
 
            $this->endMethod('processWebhookPayload', ['result' => $result, 'error' => $e->getMessage()]);
 
            $this->loggingService->logException($e, [
                'operation' => 'telegram_webhook_processing',
                'payload' => $payload
            ]);
 
            return $result;
        }
    }
 
    /**
     * Process text message
     */
    private function processTextMessage(array $message): array
    {
        $this->trackMethod('processTextMessage', ['message' => $message]);
 
        $result = $this->telegramBotService->processMessage($message);
        $result['status'] = 'success';
        $result['message'] = 'Text message processed';
        $result['input_type'] = 'text';
 
        $this->endMethod('processTextMessage', ['result' => $result]);
        return $result;
    }
 
    /**
     * Process voice message
     */
    private function processVoiceMessage(array $message): array
    {
        $this->trackMethod('processVoiceMessage', ['message' => $message]);
 
        try {
            $chatId = $message['chat']['id'];
 
            if (!$this->speechService) {
                $result = $this->createIgnoredResult('Speech service not available');
                $this->endMethod('processVoiceMessage', ['result' => $result]);
                return $result;
            }
 
            // Convert voice to text
            $voiceFileId = $message['voice']['file_id'];
            $text = $this->speechService->convertVoiceToText($voiceFileId);
 
            if (empty($text)) {
                $result = $this->createIgnoredResult('Could not convert voice to text');
                $this->endMethod('processVoiceMessage', ['result' => $result]);
                return $result;
            }
 
            // Process the converted text as a regular message
            $textMessage = array_merge($message, ['text' => $text]);
            $result = $this->processTextMessage($textMessage);
            $result['input_type'] = 'voice';
            $result['converted_text'] = $text;
 
            $this->endMethod('processVoiceMessage', ['result' => $result]);
            return $result;
 
        } catch (\Exception $e) {
            $result = [
                'success' => false,
                'status' => 'error',
                'message' => 'Voice processing failed',
                'error' => $e->getMessage()
            ];
 
            $this->endMethod('processVoiceMessage', ['result' => $result, 'error' => $e->getMessage()]);
            return $result;
        }
    }
 
    /**
     * Process audio message
     */
    private function processAudioMessage(array $message): array
    {
        $this->trackMethod('processAudioMessage', ['message' => $message]);
 
        try {
            $chatId = $message['chat']['id'];
 
            if (!$this->speechService) {
                $result = $this->createIgnoredResult('Speech service not available');
                $this->endMethod('processAudioMessage', ['result' => $result]);
                return $result;
            }
 
            // Convert audio to text
            $audioFileId = $message['audio']['file_id'];
            $text = $this->speechService->convertAudioToText($audioFileId);
 
            if (empty($text)) {
                $result = $this->createIgnoredResult('Could not convert audio to text');
                $this->endMethod('processAudioMessage', ['result' => $result]);
                return $result;
            }
 
            // Process the converted text as a regular message
            $textMessage = array_merge($message, ['text' => $text]);
            $result = $this->processTextMessage($textMessage);
            $result['input_type'] = 'audio';
            $result['converted_text'] = $text;
 
            $this->endMethod('processAudioMessage', ['result' => $result]);
            return $result;
 
        } catch (\Exception $e) {
            $result = [
                'success' => false,
                'status' => 'error',
                'message' => 'Audio processing failed',
                'error' => $e->getMessage()
            ];
 
            $this->endMethod('processAudioMessage', ['result' => $result, 'error' => $e->getMessage()]);
            return $result;
        }
    }
 
    /**
     * Process callback query
     */
    private function processCallbackQuery(array $callbackQuery): array
    {
        $this->trackMethod('processCallbackQuery', ['callback_query' => $callbackQuery]);
 
        $result = $this->telegramBotService->processCallbackQuery($callbackQuery);
        $result['status'] = 'success';
        $result['message'] = 'Callback query processed';
        $result['input_type'] = 'callback_query';
 
        $this->endMethod('processCallbackQuery', ['result' => $result]);
        return $result;
    }
 
    /**
     * Create ignored result
     */
    private function createIgnoredResult(string $message): array
    {
        return [
            'success' => false,
            'status' => 'ignored',
            'message' => $message,
            'type' => 'ignored'
        ];
    }
 
    // ========================================
    // MessageTrackingInterface Implementation
    // ========================================
 
    /**
     * Inicializa o sistema de tracking
     */
    public function initializeTracking(): void
    {
        // Tracking já é inicializado no construtor
    }
 
    /**
     * Inicia o tracking de um método
     */
    public function trackMethod(string $methodName, array $inputData = [], array $outputData = []): void
    {
        $className = class_basename($this);
        $this->flowTracker->trackMethod($className, $methodName, $inputData, $outputData);
    }
 
    /**
     * Finaliza o tracking de um método
     */
    public function endMethod(string $methodName, array $outputData = []): void
    {
        $className = class_basename($this);
        $this->flowTracker->endMethod($className, $methodName, $outputData);
    }
}

Continue para a próxima seção quando estiver pronto!

TelegramMessageProcessorService.php

<?php
 
namespace App\Services\Telegram;
 
use App\Services\Telegram\Commands\UnifiedCommandSystem;
use App\Services\Telegram\Commands\CommandResult;
use App\Services\Channels\TelegramChannel;
use App\Services\SpeechToTextService;
use App\Contracts\LoggingServiceInterface;
 
class TelegramMessageProcessorService
{
    public function __construct(
        private UnifiedCommandSystem $commandSystem,
        private TelegramAuthorizationService $authorizationService,
        private ?SpeechToTextService $speechService = null,
        private ?TelegramChannel $telegramChannel = null,
        private ?LoggingServiceInterface $loggingService = null
    ) {}
 
    public function processMessage(array $payload): array
    {
        try {
            // Check if it's a callback query (button click)
            if (isset($payload['callback_query'])) {
                return $this->processCallbackQuery($payload['callback_query']);
            }
 
            // Verify if it's a message
            if (!isset($payload['message'])) {
                $result = [
                    'success' => false,
                    'status' => 'ignored',
                    'message' => 'No message in payload'
                ];
 
                return $result;
            }
 
            $message = $payload['message'];
 
            // Process different message types
            if (isset($message['text'])) {
                return $this->processTextMessage($message);
            }
 
            if (isset($message['voice'])) {
                return $this->processVoiceMessage($message);
            }
 
            if (isset($message['audio'])) {
                return $this->processAudioMessage($message);
            }
 
            return $this->createIgnoredResult('Unsupported message type');
 
        } catch (\Exception $e) {
            $result = [
                'success' => false,
                'status' => 'error',
                'message' => 'Internal server error',
                'error' => $e->getMessage()
            ];
 
            if ($this->loggingService) {
                $this->loggingService->logException($e, [
                    'operation' => 'telegram_webhook_processing',
                    'payload' => $payload
                ]);
            }
 
            return $result;
        }
    }
 
    private function processTextMessage(array $message): array
    {
        $chatId = $message['chat']['id'];
        $text = $message['text'] ?? '';
 
        if (empty($text)) {
            return $this->createEmptyMessageResponse($chatId);
        }
 
        // Process command through unified system
        $result = $this->commandSystem->processCommand($text, $this->getContextFromMessage($message));
 
        if ($result->isSuccess()) {
            return $this->createSuccessResponse($chatId, $result);
        } else {
            return $this->createCommandNotFoundResponse($chatId, $result);
        }
    }
 
    private function processVoiceMessage(array $message): array
    {
        try {
            $chatId = $message['chat']['id'];
            $voice = $message['voice'];
 
            // Check if speech service is available
            if (!$this->speechService) {
                if ($this->telegramChannel) {
                    $this->telegramChannel->sendTextMessage(
                        "❌ Serviço de reconhecimento de voz não está disponível. Envie uma mensagem de texto.",
                        (string) $chatId
                    );
                }
 
                return $this->createVoiceConversionErrorResponse($chatId);
            }
 
            // Send processing message
            if ($this->telegramChannel) {
                $this->telegramChannel->sendTextMessage(
                    "🎤 Processando mensagem de voz...",
                    (string) $chatId
                );
            }
 
            // Download voice file
            $voiceFilePath = $this->downloadVoiceFile($voice['file_id']);
 
            if (!$voiceFilePath) {
                return $this->createVoiceConversionErrorResponse($chatId);
            }
 
            // Convert voice to text with error handling
            try {
                $text = $this->speechService->convertVoiceToText($voiceFilePath);
            } catch (\Exception $speechException) {
                if ($this->loggingService) {
                    $this->loggingService->logException($speechException, [
                        'operation' => 'speech_to_text_conversion',
                        'chat_id' => $chatId,
                        'file_path' => $voiceFilePath
                    ]);
                }
 
                // Send error message to user
                if ($this->telegramChannel) {
                    $this->telegramChannel->sendTextMessage(
                        "❌ Erro ao processar mensagem de voz. Tente novamente ou envie uma mensagem de texto.",
                        (string) $chatId
                    );
                }
 
                return $this->createVoiceConversionErrorResponse($chatId);
            }
 
            if (!$text) {
                if ($this->loggingService) {
                    $this->loggingService->logException(new \Exception('Failed to convert voice to text'), [
                        'chat_id' => $chatId,
                        'file_path' => $voiceFilePath
                    ]);
                }
 
                // Send error message to user
                if ($this->telegramChannel) {
                    $this->telegramChannel->sendTextMessage(
                        "❌ Não foi possível reconhecer o texto da mensagem de voz. Tente novamente.",
                        (string) $chatId
                    );
                }
 
                return $this->createVoiceConversionErrorResponse($chatId);
            }
 
            // Clean up voice file
            if (file_exists($voiceFilePath)) {
                unlink($voiceFilePath);
            }
 
            // Send recognized text to user
            if ($this->telegramChannel) {
                $this->telegramChannel->sendTextMessage(
                    "🎯 Texto reconhecido: *{$text}*",
                    (string) $chatId
                );
            }
 
            // Update context for voice processing
            $context = $this->getContextFromMessage($message);
            $context['type'] = 'voice';
            $context['original_voice'] = $text;
 
            // Process converted text through unified system
            $result = $this->commandSystem->processCommand($text, $context);
 
            if ($result->isSuccess()) {
                return $this->createSuccessResponse($chatId, $result);
            } else {
                return $this->createCommandNotFoundResponse($chatId, $result);
            }
 
        } catch (\Exception $e) {
            if ($this->loggingService) {
                $this->loggingService->logException($e, [
                    'operation' => 'voice_message_processing',
                    'chat_id' => $message['chat']['id'] ?? null,
                    'message' => $message
                ]);
            }
 
            return $this->createVoiceConversionErrorResponse($chatId);
        }
    }
 
    private function processCallbackQuery(array $callbackQuery): array
    {
        $chatId = $callbackQuery['message']['chat']['id'] ?? 0;
        $callbackData = $callbackQuery['data'] ?? '';
 
        if (empty($callbackData)) {
            return $this->createEmptyCallbackResponse($chatId);
        }
 
        // Process callback through unified system
        $result = $this->commandSystem->processCommand($callbackData, $this->getContextFromCallbackQuery($callbackQuery));
 
        if ($result->isSuccess()) {
            return $this->createSuccessResponse($chatId, $result);
        } else {
            return $this->createCallbackErrorResponse($chatId, $result);
        }
    }
 
    private function getContextFromMessage(array $message): array
    {
        // Check if this is a callback query
        if (isset($message['callback_query'])) {
            return $this->getContextFromCallbackQuery($message['callback_query']);
        }
 
        // Regular message
        return [
            'chat_id' => $message['chat']['id'],
            'user_id' => $message['from']['id'] ?? null,
            'type' => $this->determineMessageType($message),
            'timestamp' => $message['date'] ?? time(),
            'user_permissions' => $this->getUserPermissions($message)
        ];
    }
 
    private function getContextFromCallbackQuery(array $callbackQuery): array
    {
        return [
            'chat_id' => $callbackQuery['message']['chat']['id'] ?? 0,
            'user_id' => $callbackQuery['from']['id'] ?? null,
            'type' => 'callback_query',
            'timestamp' => $callbackQuery['date'] ?? time(),
            'user_permissions' => $this->getUserPermissions($callbackQuery)
        ];
    }
 
    private function determineMessageType(array $message): string
    {
        if (isset($message['callback_query'])) {
            return 'callback_query';
        }
 
        if (isset($message['voice'])) {
            return 'voice';
        }
 
        if (isset($message['audio'])) {
            return 'audio';
        }
 
        if (isset($message['text'])) {
            return 'text';
        }
 
        return 'unknown';
    }
 
    private function getUserPermissions(array $message): array
    {
        // Extract user permissions from message or callback query
        $userId = null;
 
        if (isset($message['from']['id'])) {
            // Regular message
            $userId = $message['from']['id'];
        } elseif (isset($message['callback_query']['from']['id'])) {
            // Callback query wrapped in payload
            $userId = $message['callback_query']['from']['id'];
        }
 
        if (!$userId) {
            return ['user'];
        }
 
        // TODO: Implement actual permission checking
        // For now, return default permissions
        return ['user'];
    }
 
    private function createSuccessResponse(int $chatId, CommandResult $result): array
    {
        $data = $result->getData();
 
        return [
            'success' => true,
            'chat_id' => $chatId,
            'type' => $result->getType(),
            'data' => $data,
            'command_info' => $result->getCommandMatch() ? [
                'command_id' => $result->getCommandMatch()->getCommand()->getId(),
                'confidence' => $result->getCommandMatch()->getConfidence()
            ] : null
        ];
    }
 
    private function createCommandNotFoundResponse(int $chatId, CommandResult $result): array
    {
        $data = $result->getData();
        $fallbackMessage = $data['fallback_message'] ?? 'Comando não encontrado';
 
        // Send the fallback message to the user in Telegram chat
        if ($this->telegramChannel) {
            $this->telegramChannel->sendTextMessage(
                $fallbackMessage,
                (string) $chatId
            );
        }
 
        return [
            'success' => false,
            'chat_id' => $chatId,
            'type' => 'command_not_found',
            'message' => $fallbackMessage,
            'suggestions' => $data['suggestions'] ?? [],
            'data' => $data
        ];
    }
 
    private function createEmptyMessageResponse(int $chatId): array
    {
        return [
            'success' => false,
            'chat_id' => $chatId,
            'type' => 'empty_message',
            'message' => 'Mensagem vazia recebida.',
            'data' => []
        ];
    }
 
    private function createVoiceConversionErrorResponse(int $chatId): array
    {
        return [
            'success' => false,
            'chat_id' => $chatId,
            'type' => 'voice_conversion_error',
            'message' => 'Erro ao converter mensagem de voz.',
            'data' => []
        ];
    }
 
    private function createEmptyCallbackResponse(int $chatId): array
    {
        return [
            'success' => false,
            'chat_id' => $chatId,
            'type' => 'empty_callback',
            'message' => 'Dados de callback vazios.',
            'data' => []
        ];
    }
 
    private function createCallbackErrorResponse(int $chatId, CommandResult $result): array
    {
        return [
            'success' => false,
            'chat_id' => $chatId,
            'type' => 'callback_error',
            'message' => 'Erro ao processar callback.',
            'data' => $result->getData()
        ];
    }
 
    private function createIgnoredResult(string $message): array
    {
        return [
            'success' => false,
            'status' => 'ignored',
            'message' => $message
        ];
    }
 
    // Additional methods for audio processing and file downloads...
    // (processAudioMessage, downloadVoiceFile, downloadAudioFile, etc.)
}

TelegramRepository.php

<?php
 
namespace App\Repositories;
 
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Cache;
 
class TelegramRepository
{
    private const CACHE_TTL = 3600; // 1 hour
    private const CACHE_PREFIX = 'telegram:';
 
    /**
     * Get authorized users
     */
    public function getAuthorizedUsers(): array
    {
        return Config::get('services.telegram.recipients', []);
    }
 
    /**
     * Check if user is authorized
     */
    public function isUserAuthorized(int $chatId): bool
    {
        $authorizedUsers = $this->getAuthorizedUsers();
        return in_array($chatId, $authorizedUsers);
    }
 
    /**
     * Get bot configuration
     */
    public function getBotConfig(): array
    {
        return [
            'enabled' => Config::get('services.telegram.enabled', false),
            'bot_token' => Config::get('services.telegram.bot_token'),
            'recipients' => $this->getAuthorizedUsers(),
        ];
    }
 
    /**
     * Cache webhook info
     */
    public function cacheWebhookInfo(array $webhookInfo): void
    {
        Cache::put(
            self::CACHE_PREFIX . 'webhook_info',
            $webhookInfo,
            self::CACHE_TTL
        );
    }
 
    /**
     * Get cached webhook info
     */
    public function getCachedWebhookInfo(): ?array
    {
        return Cache::get(self::CACHE_PREFIX . 'webhook_info');
    }
 
    /**
     * Clear webhook cache
     */
    public function clearWebhookCache(): void
    {
        Cache::forget(self::CACHE_PREFIX . 'webhook_info');
    }
 
    /**
     * Cache message processing result
     */
    public function cacheMessageResult(int $chatId, array $result): void
    {
        $key = self::CACHE_PREFIX . "message_result:{$chatId}";
        Cache::put($key, $result, self::CACHE_TTL);
    }
 
    /**
     * Get cached message result
     */
    public function getCachedMessageResult(int $chatId): ?array
    {
        $key = self::CACHE_PREFIX . "message_result:{$chatId}";
        return Cache::get($key);
    }
 
    /**
     * Store webhook log
     */
    public function storeWebhookLog(array $payload, array $result): void
    {
        $logData = [
            'timestamp' => now()->toISOString(),
            'payload' => $payload,
            'result' => $result,
            'ip' => request()->ip(),
            'user_agent' => request()->userAgent(),
        ];
 
        // Store in cache for recent logs
        $logs = Cache::get(self::CACHE_PREFIX . 'recent_logs', []);
        $logs[] = $logData;
 
        // Keep only last 100 logs
        if (count($logs) > 100) {
            $logs = array_slice($logs, -100);
        }
 
        Cache::put(self::CACHE_PREFIX . 'recent_logs', $logs, self::CACHE_TTL);
    }
 
    /**
     * Get recent webhook logs
     */
    public function getRecentWebhookLogs(int $limit = 50): array
    {
        $logs = Cache::get(self::CACHE_PREFIX . 'recent_logs', []);
        return array_slice($logs, -$limit);
    }
 
    /**
     * Get webhook statistics
     */
    public function getWebhookStats(): array
    {
        $logs = $this->getRecentWebhookLogs(1000);
 
        $stats = [
            'total_requests' => count($logs),
            'successful_requests' => 0,
            'failed_requests' => 0,
            'ignored_requests' => 0,
            'message_requests' => 0,
            'callback_requests' => 0,
        ];
 
        foreach ($logs as $log) {
            $result = $log['result'] ?? [];
            $status = $result['status'] ?? 'unknown';
 
            switch ($status) {
                case 'success':
                    $stats['successful_requests']++;
                    break;
                case 'error':
                    $stats['failed_requests']++;
                    break;
                case 'ignored':
                    $stats['ignored_requests']++;
                    break;
            }
 
            // Count request types
            if (isset($log['payload']['message'])) {
                $stats['message_requests']++;
            }
            if (isset($log['payload']['callback_query'])) {
                $stats['callback_requests']++;
            }
        }
 
        return $stats;
    }
}

📝 Seção 1: Controllers e Rotas

TelegramWebhookController.php

<?php
 
namespace App\Http\Controllers\Api;
 
use App\Http\Controllers\Controller;
use App\Http\Requests\TelegramWebhookRequest;
use App\Http\Requests\TelegramWebhookSetupRequest;
use App\Http\Resources\TelegramWebhookResource;
use App\Services\TelegramBotService;
use App\Services\TelegramWebhookService;
use App\Services\Telegram\TelegramMessageProcessorService;
use App\Services\Telegram\TelegramWebhookValidationService;
use App\Services\Channels\TelegramChannel;
use App\Contracts\LoggingServiceInterface;
use App\Contracts\MessageFlowTrackerInterface;
use Illuminate\Http\JsonResponse;
 
class TelegramWebhookController extends Controller
{
    public function __construct(
        private TelegramBotService $telegramBotService,
        private TelegramChannel $telegramChannel,
        private TelegramWebhookService $webhookService,
        private TelegramMessageProcessorService $messageProcessor,
        private TelegramWebhookValidationService $webhookValidationService,
        private LoggingServiceInterface $loggingService,
        private MessageFlowTrackerInterface $flowTracker
    ) {}
 
    /**
     * Handle Telegram webhook
     */
    public function handle(TelegramWebhookRequest $request): JsonResponse
    {
        $startTime = microtime(true);
 
        // Inicializa o tracker com ID único
        $this->flowTracker->startTracking(uniqid('webhook_', true));
 
        try {
            // Check if validation failed
            if ($request->has('validation_errors')) {
                $validationErrors = $request->input('validation_errors');
                $errorMessage = $this->createValidationErrorMessage($validationErrors);
 
                // Send friendly error message to user via Telegram
                $this->sendFriendlyErrorMessage($request->all(), $errorMessage);
 
                return TelegramWebhookResource::ignored('Validation failed - friendly message sent to user')
                    ->response()
                    ->setStatusCode(200);
            }
 
            $payload = $request->validated();
 
            // Validate payload structure first
            $validation = $this->webhookService->validatePayload($payload);
 
            if (!$validation['valid']) {
                // Send friendly error message to user via Telegram
                $this->sendFriendlyErrorMessage($payload, $validation['message']);
 
                return TelegramWebhookResource::ignored($validation['message'])
                    ->response()
                    ->setStatusCode(200);
            }
 
            // Validate webhook and mark as processing (after payload validation)
            $updateId = $payload['update_id'] ?? null;
            $skipDuplicateCheck = app()->environment('testing');
            if (!$this->webhookValidationService->validateAndMarkProcessing($updateId, $skipDuplicateCheck)) {
                return TelegramWebhookResource::success('Duplicate webhook ignored', [
                    'success' => true,
                    'status' => 'ignored',
                    'message' => 'Duplicate webhook ignored',
                    'update_id' => $updateId
                ])
                    ->response()
                    ->setStatusCode(200);
            }
 
            // Process the webhook payload with timeout protection
            $result = $this->processWithTimeout(function () use ($payload) {
                return $this->messageProcessor->processWebhookPayload($payload);
            }, 25); // 25 seconds timeout
 
            // Gera relatório do fluxo APÓS o processamento
            $flowReport = $this->flowTracker->generateFlowReport($payload);
            $userReport = $this->flowTracker->generateUserReport($payload);
 
            // Finaliza o tracking
            $this->flowTracker->endTracking();
 
            // Se habilitado, envia relatório para o usuário
            if (config('message-flow.tracking.send_to_user', false)) {
                $this->sendFlowReportToUser($payload, $userReport);
            }
 
            if (config('message-flow.enabled', false)) {
                $this->loggingService->logTelegramEvent('message_flow_report', [
                    'flow_report' => $flowReport,
                    'user_report' => $userReport,
                    'payload' => $payload
                ], 'info');
            }
 
            // Check if the result is valid and has the expected structure
            if (!is_array($result) || !isset($result['success'])) {
                $this->loggingService->logTelegramEvent('telegram_webhook_invalid_result', [
                    'error' => 'Invalid result structure from message processor',
                    'result' => $result,
                    'payload' => $payload,
                    'telegram_update_id' => $request->input('update_id'),
                    'timestamp' => now()->toISOString()
                ], 'error');
 
                // Send friendly error message to user
                $this->sendFriendlyErrorMessage($payload, 'Desculpe, ocorreu um erro interno. Tente novamente em alguns instantes.');
 
                return TelegramWebhookResource::error('Invalid processing result')
                    ->response()
                    ->setStatusCode(500);
            }
 
            // Check if this is a normal response (not an error) - check status first
            $isNormalResponse = isset($result['type']) && in_array($result['type'], [
                'command_not_found',
                'ignored',
                'unauthorized',
                'unsupported',
                'empty_message',
                'voice_conversion_error',
                'audio_conversion_error'
            ]);
 
            if ($isNormalResponse) {
                // Send fallback message to user for command_not_found
                if ($result['type'] === 'command_not_found') {
                    $fallbackMessage = $this->createCommandNotFoundFallbackMessage($result);
                    $this->sendFriendlyErrorMessage($payload, $fallbackMessage);
                }
 
                // Use appropriate resource method based on status
                if (isset($result['status']) && $result['status'] === 'ignored') {
                    return TelegramWebhookResource::ignored($result['message'] ?? 'Message ignored', $result)
                        ->response()
                        ->setStatusCode(200);
                }
 
                return TelegramWebhookResource::success($result['message'] ?? 'Message processed', $result)
                    ->response()
                    ->setStatusCode(200);
            }
 
            // Check if the message was processed successfully
            if ($result['success']) {
                return TelegramWebhookResource::success($result['message'] ?? 'Message processed successfully', $result)
                    ->response()
                    ->setStatusCode(200);
            }
 
            // Handle actual errors (return 500)
            $this->loggingService->logTelegramEvent('telegram_webhook_processing_failed', [
                'error' => 'Message processing failed',
                'error_message' => $result['message'] ?? 'Unknown error',
                'result' => $result,
                'payload' => $payload,
                'telegram_update_id' => $request->input('update_id'),
                'timestamp' => now()->toISOString()
            ], 'error');
 
            // Send friendly error message to user
            $this->sendFriendlyErrorMessage($payload, $result['message'] ?? 'Desculpe, ocorreu um erro ao processar sua mensagem. Tente novamente.');
 
            return TelegramWebhookResource::error($result['message'] ?? 'Message processing failed', $result)
                ->response()
                ->setStatusCode(500);
 
        } catch (\Exception $e) {
            $duration = (microtime(true) - $startTime) * 1000;
 
            $this->loggingService->logException($e, [
                'operation' => 'telegram_webhook_processing',
                'chat_id' => $request->input('message.chat.id'),
                'user_id' => $request->input('message.from.id'),
                'processing_time_ms' => round($duration, 2)
            ]);
 
            // Send friendly error message to user even for exceptions
            $this->sendFriendlyErrorMessage($request->all(), 'Desculpe, ocorreu um erro inesperado. Nossa equipe foi notificada.');
 
            return TelegramWebhookResource::error('Internal server error')
                ->response()
                ->setStatusCode(500);
        }
    }
 
    /**
     * Set webhook URL for Telegram bot
     */
    public function setWebhook(TelegramWebhookSetupRequest $request): JsonResponse
    {
        try {
            $webhookUrl = $request->validated()['webhook_url'];
            $result = $this->webhookService->setWebhook($webhookUrl);
 
            if (!$result['success']) {
                return TelegramWebhookResource::error($result['message'], $result)
                    ->response()
                    ->setStatusCode(400);
            }
 
            return TelegramWebhookResource::success($result['message'], $result)
                ->response()
                ->setStatusCode(200);
 
        } catch (\Exception $e) {
            $this->loggingService->logException($e, [
                'operation' => 'telegram_webhook_setup',
                'webhook_url' => $request->validated()['webhook_url'] ?? 'unknown'
            ]);
 
            return TelegramWebhookResource::error('Internal server error')
                ->response()
                ->setStatusCode(500);
        }
    }
 
    /**
     * Get webhook info
     */
    public function getWebhookInfo(): JsonResponse
    {
        try {
            $this->loggingService->logTelegramEvent('telegram_webhook_info_request', [
                'action' => 'get_webhook_info'
            ], 'info');
 
            $result = $this->webhookService->getWebhookInfo();
 
            if (!$result['success']) {
                $this->loggingService->logTelegramEvent('telegram_webhook_info_failed', [
                    'error' => $result['message'],
                    'result' => $result
                ], 'error');
 
                return TelegramWebhookResource::error($result['message'], $result)
                    ->response()
                    ->setStatusCode(400);
            }
 
            return TelegramWebhookResource::success('Webhook info retrieved', $result)
                ->response()
                ->setStatusCode(200);
 
        } catch (\Exception $e) {
            $this->loggingService->logException($e, [
                'operation' => 'telegram_webhook_info'
            ]);
 
            return TelegramWebhookResource::error('Internal server error')
                ->response()
                ->setStatusCode(500);
        }
    }
 
    /**
     * Delete webhook
     */
    public function deleteWebhook(): JsonResponse
    {
        try {
            $this->loggingService->logTelegramEvent('telegram_webhook_deletion', [
                'action' => 'delete_webhook'
            ], 'info');
 
            $result = $this->webhookService->deleteWebhook();
 
            if (!$result['success']) {
                $this->loggingService->logTelegramEvent('telegram_webhook_deletion_failed', [
                    'error' => $result['message'],
                    'result' => $result
                ], 'error');
 
                return TelegramWebhookResource::error($result['message'], $result)
                    ->response()
                    ->setStatusCode(400);
            }
 
            $this->loggingService->logTelegramEvent('telegram_webhook_deletion_success', [
                'result' => $result
            ], 'success');
 
            return TelegramWebhookResource::success($result['message'], $result)
                ->response()
                ->setStatusCode(200);
 
        } catch (\Exception $e) {
            $this->loggingService->logException($e, [
                'operation' => 'telegram_webhook_deletion'
            ]);
 
            return TelegramWebhookResource::error('Internal server error')
                ->response()
                ->setStatusCode(500);
        }
    }
 
    /**
     * Test bot functionality
     */
    public function test(): JsonResponse
    {
        try {
            $this->loggingService->logTelegramEvent('telegram_bot_test', [
                'action' => 'test_bot'
            ], 'info');
 
            $result = $this->webhookService->testBot();
 
            if (!$result['success']) {
                $this->loggingService->logTelegramEvent('telegram_bot_test_failed', [
                    'error' => $result['message'],
                    'result' => $result
                ], 'error');
 
                return TelegramWebhookResource::error($result['message'], $result)
                    ->response()
                    ->setStatusCode(400);
            }
 
            $this->loggingService->logTelegramEvent('telegram_bot_test_success', [
                'result' => $result
            ], 'success');
 
            return TelegramWebhookResource::success($result['message'], $result)
                ->response()
                ->setStatusCode(200);
 
        } catch (\Exception $e) {
            $this->loggingService->logException($e, [
                'operation' => 'telegram_bot_test'
            ]);
 
            return TelegramWebhookResource::error('Test failed: ' . $e->getMessage())
                ->response()
                ->setStatusCode(500);
        }
    }
 
    // ... (métodos auxiliares privados serão adicionados na próxima seção)
}

TelegramStatsController.php

<?php
 
namespace App\Http\Controllers\Api;
 
use App\Http\Controllers\Controller;
use App\Http\Resources\TelegramWebhookResource;
use App\Services\TelegramLoggingService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
 
class TelegramStatsController extends Controller
{
    public function __construct(
        private TelegramLoggingService $loggingService
    ) {}
 
    /**
     * Get webhook statistics
     */
    public function getStats(): JsonResponse
    {
        try {
            $stats = $this->loggingService->getWebhookStats();
 
            return TelegramWebhookResource::success('Statistics retrieved successfully', [
                'statistics' => $stats
            ])
            ->response()
            ->setStatusCode(200);
 
        } catch (\Exception $e) {
            return TelegramWebhookResource::error('Failed to retrieve statistics: ' . $e->getMessage())
                ->response()
                ->setStatusCode(500);
        }
    }
 
    /**
     * Get recent webhook logs
     */
    public function getRecentLogs(Request $request): JsonResponse
    {
        try {
            $limit = $request->get('limit', 50);
            $limit = min(max((int) $limit, 1), 100); // Limit between 1 and 100
 
            $logs = $this->loggingService->getRecentLogs($limit);
 
            return TelegramWebhookResource::success('Recent logs retrieved successfully', [
                'logs' => $logs,
                'count' => count($logs),
                'limit' => $limit
            ])
            ->response()
            ->setStatusCode(200);
 
        } catch (\Exception $e) {
            return TelegramWebhookResource::error('Failed to retrieve logs: ' . $e->getMessage())
                ->response()
                ->setStatusCode(500);
        }
    }
 
    /**
     * Get webhook health status
     */
    public function getHealthStatus(): JsonResponse
    {
        try {
            $stats = $this->loggingService->getWebhookStats();
 
            // Calculate health metrics
            $totalRequests = $stats['total_requests'] ?? 0;
            $successfulRequests = $stats['successful_requests'] ?? 0;
            $failedRequests = $stats['failed_requests'] ?? 0;
 
            $successRate = $totalRequests > 0 ? ($successfulRequests / $totalRequests) * 100 : 0;
            $errorRate = $totalRequests > 0 ? ($failedRequests / $totalRequests) * 100 : 0;
 
            $healthStatus = [
                'status' => $successRate >= 90 ? 'healthy' : ($successRate >= 70 ? 'warning' : 'critical'),
                'success_rate' => round($successRate, 2),
                'error_rate' => round($errorRate, 2),
                'total_requests' => $totalRequests,
                'successful_requests' => $successfulRequests,
                'failed_requests' => $failedRequests,
                'ignored_requests' => $stats['ignored_requests'] ?? 0,
                'message_requests' => $stats['message_requests'] ?? 0,
                'callback_requests' => $stats['callback_requests'] ?? 0,
                'last_updated' => now()->toISOString(),
            ];
 
            return TelegramWebhookResource::success('Health status retrieved successfully', [
                'health' => $healthStatus
            ])
            ->response()
            ->setStatusCode(200);
 
        } catch (\Exception $e) {
            return TelegramWebhookResource::error('Failed to retrieve health status: ' . $e->getMessage())
                ->response()
                ->setStatusCode(500);
        }
    }
}

Rotas (routes/api.php)

// =============================================================================
// TELEGRAM BOT ROUTES
// =============================================================================
 
Route::prefix('telegram')->group(function () {
    //Route::middleware('telegram.webhook.secret')->group(function () {
        Route::post('/webhook', [TelegramWebhookController::class, 'handle']);                  // POST /api/telegram/webhook
    //});
 
    // Outras rotas sem validação de secret (gerenciamento interno)
    Route::post('/set-webhook', [TelegramWebhookController::class, 'setWebhook']);                  // POST /api/telegram/set-webhook
    Route::get('/webhook-info', [TelegramWebhookController::class, 'getWebhookInfo']);              // GET /api/telegram/webhook-info
    Route::delete('/webhook', [TelegramWebhookController::class, 'deleteWebhook']);                 // DELETE /api/telegram/webhook
 
    // Testing and monitoring
    Route::post('/test', [TelegramWebhookController::class, 'test']);                               // POST /api/telegram/test
 
    // Statistics and monitoring
    Route::prefix('stats')->group(function () {
        Route::get('/', [TelegramStatsController::class, 'getStats']);                              // GET /api/telegram/stats
        Route::get('/logs', [TelegramStatsController::class, 'getRecentLogs']);                     // GET /api/telegram/stats/logs
        Route::get('/health', [TelegramStatsController::class, 'getHealthStatus']);                 // GET /api/telegram/stats/health
    });
});

📝 Seção 2: Services e Processamento

TelegramWebhookService.php

<?php
 
namespace App\Services;
 
use Illuminate\Support\Facades\Http;
use App\Contracts\LoggingServiceInterface;
 
class TelegramWebhookService
{
    private string $botToken;
    private string $apiUrl;
 
    public function __construct(
        private LoggingServiceInterface $loggingService
    ) {
        $this->botToken = config('services.telegram.bot_token');
        $this->apiUrl = "https://api.telegram.org/bot{$this->botToken}";
    }
 
    /**
     * Set webhook URL for Telegram bot
     */
    public function setWebhook(string $webhookUrl): array
    {
        try {
            $response = Http::post("{$this->apiUrl}/setWebhook", [
                'url' => $webhookUrl
            ]);
 
            if ($response->successful()) {
                $data = $response->json();
 
                $result = [
                    'success' => true,
                    'message' => 'Webhook set successfully',
                    'data' => $data
                ];
 
                $this->loggingService->logBusinessOperation('telegram_webhook_setup_success', [
                    'webhook_url' => $webhookUrl,
                    'result' => $result
                ], 'success');
 
                return $result;
            }
 
            $result = [
                'success' => false,
                'message' => 'Failed to set webhook',
                'error' => $response->json()
            ];
 
            $this->loggingService->logBusinessOperation('telegram_webhook_setup_failed', [
                'webhook_url' => $webhookUrl,
                'error' => $result['error']
            ], 'error');
 
            return $result;
 
        } catch (\Exception $e) {
            $result = [
                'success' => false,
                'message' => 'Internal server error',
                'error' => $e->getMessage()
            ];
 
            $this->loggingService->logException($e, [
                'operation' => 'telegram_webhook_setup',
                'webhook_url' => $webhookUrl
            ]);
 
            return $result;
        }
    }
 
    /**
     * Get webhook info
     */
    public function getWebhookInfo(): array
    {
        try {
            $this->loggingService->logBusinessOperation('telegram_webhook_info_request', [
                'action' => 'get_webhook_info'
            ], 'info');
 
            $response = Http::get("{$this->apiUrl}/getWebhookInfo");
 
            if ($response->successful()) {
                $data = $response->json();
 
                $result = [
                    'success' => true,
                    'data' => $data
                ];
 
                $this->loggingService->logBusinessOperation('telegram_webhook_info_success', [
                    'result' => $result
                ], 'success');
 
                return $result;
            }
 
            $result = [
                'success' => false,
                'message' => 'Failed to get webhook info',
                'error' => $response->json()
            ];
 
            $this->loggingService->logBusinessOperation('telegram_webhook_info_failed', [
                'error' => $result['error']
            ], 'error');
 
            return $result;
 
        } catch (\Exception $e) {
            $this->loggingService->logException($e, [
                'operation' => 'telegram_webhook_info'
            ]);
 
            return [
                'success' => false,
                'message' => 'Internal server error',
                'error' => $e->getMessage()
            ];
        }
    }
 
    /**
     * Delete webhook
     */
    public function deleteWebhook(): array
    {
        try {
            $this->loggingService->logBusinessOperation('telegram_webhook_deletion_attempt', [
                'action' => 'delete_webhook'
            ], 'info');
 
            $response = Http::post("{$this->apiUrl}/deleteWebhook");
 
            if ($response->successful()) {
                $data = $response->json();
 
                $result = [
                    'success' => true,
                    'message' => 'Webhook deleted successfully',
                    'data' => $data
                ];
 
                $this->loggingService->logBusinessOperation('telegram_webhook_deletion_success', [
                    'result' => $result
                ], 'success');
 
                return $result;
            }
 
            $result = [
                'success' => false,
                'message' => 'Failed to delete webhook',
                'error' => $response->json()
            ];
 
            $this->loggingService->logBusinessOperation('telegram_webhook_deletion_failed', [
                'error' => $result['error']
            ], 'error');
 
            return $result;
 
        } catch (\Exception $e) {
            $result = [
                'success' => false,
                'message' => 'Internal server error',
                'error' => $e->getMessage()
            ];
 
            $this->loggingService->logException($e, [
                'operation' => 'telegram_webhook_deletion'
            ]);
 
            return $result;
        }
    }
 
    /**
     * Test bot functionality
     */
    public function testBot(): array
    {
        try {
            $this->loggingService->logBusinessOperation('telegram_bot_test_attempt', [
                'action' => 'test_bot'
            ], 'info');
 
            $recipients = config('services.telegram.recipients', []);
 
            if (empty($recipients)) {
                $result = [
                    'success' => false,
                    'message' => 'No recipients configured'
                ];
 
                $this->loggingService->logBusinessOperation('telegram_bot_test_failed', [
                    'error' => 'No recipients configured'
                ], 'error');
 
                return $result;
            }
 
            $results = [];
            foreach ($recipients as $recipient) {
                $result = $this->sendTestMessage($recipient);
                $results[$recipient] = $result;
            }
 
            $successCount = count(array_filter($results, fn($r) => $r['success']));
 
            $result = [
                'success' => $successCount > 0,
                'message' => 'Test completed',
                'sent_to' => $successCount,
                'total_recipients' => count($recipients),
                'results' => $results
            ];
 
            $this->loggingService->logBusinessOperation('telegram_bot_test_success', [
                'sent_to' => $successCount,
                'total_recipients' => count($recipients),
                'result' => $result
            ], 'success');
 
            return $result;
 
        } catch (\Exception $e) {
            $result = [
                'success' => false,
                'message' => 'Test failed: ' . $e->getMessage()
            ];
 
            $this->loggingService->logException($e, [
                'operation' => 'telegram_bot_test'
            ]);
 
            return $result;
        }
    }
 
    /**
     * Send test message to specific recipient
     */
    private function sendTestMessage(string $recipient): array
    {
        try {
            $testMessage = "🧪 *Teste do Bot*\n\n" .
                          "Este é um teste do bot de relatórios do Rei do Óleo.\n" .
                          "Se você recebeu esta mensagem, o bot está funcionando!\n\n" .
                          "Use `/help` para ver os comandos disponíveis.\n\n" .
                          "⏰ Teste realizado em: " . now()->format('d/m/Y H:i:s');
 
            $response = Http::post("{$this->apiUrl}/sendMessage", [
                'chat_id' => $recipient,
                'text' => $testMessage,
                'parse_mode' => 'Markdown'
            ]);
 
            if ($response->successful()) {
                $this->loggingService->logBusinessOperation('test_message_sent_successfully', [
                    'chat_id' => $recipient,
                    'message_type' => 'test'
                ], 'info');
 
                return [
                    'success' => true,
                    'message' => 'Test message sent successfully'
                ];
            }
 
            return [
                'success' => false,
                'error' => $response->json()['description'] ?? 'Unknown error'
            ];
 
        } catch (\Exception $e) {
            $this->loggingService->logException($e, [
                'operation' => 'telegram_test_message_send',
                'recipient' => $recipient
            ]);
 
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
 
    /**
     * Validate webhook payload
     */
    public function validatePayload(array $payload): array
    {
        if (!isset($payload['update_id'])) {
            return [
                'valid' => false,
                'message' => 'Missing update_id in payload'
            ];
        }
 
        if (!isset($payload['message']) && !isset($payload['callback_query'])) {
            return [
                'valid' => false,
                'message' => 'No message or callback_query in payload'
            ];
        }
 
        // Check if it's a message and validate message structure
        if (isset($payload['message'])) {
            $message = $payload['message'];
 
            // Check if message has required fields
            if (!isset($message['chat']['id']) || !isset($message['from']['id'])) {
                return [
                    'valid' => false,
                    'message' => 'Message missing required chat or user information'
                ];
            }
 
            // Check if message has any content (text, voice, audio, photo, etc.)
            $hasContent = isset($message['text']) ||
                         isset($message['voice']) ||
                         isset($message['audio']) ||
                         isset($message['photo']) ||
                         isset($message['document']) ||
                         isset($message['video']) ||
                         isset($message['sticker']) ||
                         isset($message['location']) ||
                         isset($message['contact']);
 
            if (!$hasContent) {
                return [
                    'valid' => false,
                    'message' => 'Message has no recognizable content'
                ];
            }
        }
 
        return [
            'valid' => true,
            'type' => isset($payload['callback_query']) ? 'callback_query' : 'message'
        ];
    }
}

TelegramBotService.php

<?php
 
namespace App\Services;
 
use App\Services\Telegram\Commands\UnifiedCommandSystem;
use App\Services\Telegram\TelegramAuthorizationService;
use App\Services\Telegram\TelegramMenuBuilder;
use App\Contracts\LoggingServiceInterface;
use App\Contracts\MessageFlowTrackerInterface;
use App\Contracts\MessageTrackingInterface;
 
class TelegramBotService implements MessageTrackingInterface
{
    public function __construct(
        private UnifiedCommandSystem $commandSystem,
        private TelegramAuthorizationService $authorizationService,
        private TelegramMenuBuilder $menuBuilder,
        private LoggingServiceInterface $loggingService,
        private MessageFlowTrackerInterface $flowTracker
    ) {
        $this->initializeTracking();
    }
 
    /**
     * Process incoming message from Telegram webhook
     */
    public function processMessage(array $message): array
    {
        $this->trackMethod('processMessage', ['message' => $message]);
 
        try {
            $chatId = $message['chat']['id'];
            $text = $message['text'] ?? '';
            $from = $message['from'] ?? [];
 
            // Check if user is authorized
            if (!$this->authorizationService->isAuthorizedUser($chatId)) {
                $result = $this->menuBuilder->buildUnauthorizedMessage($chatId);
                $this->endMethod('processMessage', ['result' => $result, 'status' => 'unauthorized']);
                return $result;
            }
 
            // Process command using UnifiedCommandSystem
            $context = [
                'chat_id' => $chatId,
                'user_id' => $from['id'] ?? null,
                'type' => 'text',
                'timestamp' => time(),
                'user_permissions' => ['user'] // TODO: Get real permissions
            ];
 
            $result = $this->commandSystem->processCommand($text, $context);
 
            if ($result->isSuccess()) {
                $data = $result->getData();
                $response = [
                    'success' => true,
                    'chat_id' => $chatId,
                    'type' => $result->getType(),
                    'data' => $data,
                    'command_info' => $result->getCommandMatch() ? [
                        'command_id' => $result->getCommandMatch()->getCommand()->getId(),
                        'confidence' => $result->getCommandMatch()->getConfidence()
                    ] : null
                ];
 
                $this->endMethod('processMessage', ['result' => $response, 'status' => 'success']);
                return $response;
            } else {
                $data = $result->getData();
                $fallbackMessage = $data['fallback_message'] ?? 'Comando não encontrado';
 
                $response = [
                    'success' => false,
                    'chat_id' => $chatId,
                    'type' => 'command_not_found',
                    'message' => $fallbackMessage,
                    'suggestions' => $data['suggestions'] ?? [],
                    'data' => $data
                ];
 
                $this->endMethod('processMessage', ['result' => $response, 'status' => 'command_not_found']);
                return $response;
            }
 
        } catch (\Exception $e) {
            $this->loggingService->logException($e, [
                'operation' => 'telegram_message_processing',
                'chat_id' => $message['chat']['id'] ?? null,
                'user_id' => $message['from']['id'] ?? null,
                'message' => $message
            ]);
 
            $errorResponse = [
                'success' => false,
                'chat_id' => $chatId,
                'type' => 'error',
                'message' => 'Erro interno do sistema',
                'data' => []
            ];
 
            $this->endMethod('processMessage', ['result' => $errorResponse, 'error' => $e->getMessage()]);
            return $errorResponse;
        }
    }
 
    /**
     * Process callback query from inline keyboard buttons
     */
    public function processCallbackQuery(array $callbackQuery): array
    {
        try {
            $chatId = $callbackQuery['message']['chat']['id'];
            $messageId = $callbackQuery['message']['message_id'] ?? null;
            $callbackData = $callbackQuery['data'] ?? '';
            $from = $callbackQuery['from'] ?? [];
 
            // Check if user is authorized
            if (!$this->authorizationService->isAuthorizedUser($chatId)) {
                return $this->menuBuilder->buildUnauthorizedMessage($chatId);
            }
 
            // Process callback using UnifiedCommandSystem
            $context = [
                'chat_id' => $chatId,
                'user_id' => $from['id'] ?? null,
                'type' => 'callback_query',
                'timestamp' => time(),
                'user_permissions' => ['user'], // TODO: Get real permissions
                'callback_data' => $callbackData
            ];
 
            $result = $this->commandSystem->processCommand($callbackData, $context);
 
            if ($result->isSuccess()) {
                $data = $result->getData();
                return [
                    'success' => true,
                    'chat_id' => $chatId,
                    'type' => $result->getType(),
                    'data' => $data,
                    'command_info' => $result->getCommandMatch() ? [
                        'command_id' => $result->getCommandMatch()->getCommand()->getId(),
                        'confidence' => $result->getCommandMatch()->getConfidence()
                    ] : null
                ];
            } else {
                $data = $result->getData();
                $fallbackMessage = $data['fallback_message'] ?? 'Ação não encontrada';
 
                return [
                    'success' => false,
                    'chat_id' => $chatId,
                    'type' => 'callback_not_found',
                    'message' => $fallbackMessage,
                    'suggestions' => $data['suggestions'] ?? [],
                    'data' => $data
                ];
            }
 
        } catch (\Exception $e) {
            $this->loggingService->logException($e, [
                'operation' => 'telegram_callback_processing',
                'chat_id' => $callbackQuery['message']['chat']['id'] ?? null,
                'user_id' => $callbackQuery['from']['id'] ?? null,
                'callback_query' => $callbackQuery
            ]);
 
            return [
                'success' => false,
                'chat_id' => $chatId,
                'type' => 'error',
                'message' => 'Erro interno do sistema',
                'data' => []
            ];
        }
    }
 
    /**
     * Send error message to user via Telegram
     */
    public function sendErrorMessage(int $chatId, string $errorMessage): array
    {
        try {
            // Create keyboard with helpful options
            $keyboard = [
                [
                    ['text' => '❓ Ajuda', 'callback_data' => 'help'],
                    ['text' => '🏠 Menu Principal', 'callback_data' => 'main_menu']
                ],
                [
                    ['text' => '📋 Comandos', 'callback_data' => 'commands_list'],
                    ['text' => '🔄 Tentar Novamente', 'callback_data' => 'retry']
                ]
            ];
 
            // Send error message with helpful keyboard using menuBuilder
            $result = $this->menuBuilder->buildMainMenu($chatId);
 
            $this->loggingService->logTelegramEvent('telegram_error_message_sent', [
                'chat_id' => $chatId,
                'error_message' => $errorMessage,
                'result' => $result
            ], 'info');
 
            return [
                'success' => true,
                'chat_id' => $chatId,
                'type' => 'error_message_sent',
                'message' => 'Error message sent to user',
                'data' => $result
            ];
 
        } catch (\Exception $e) {
            $this->loggingService->logException($e, [
                'operation' => 'send_error_message',
                'chat_id' => $chatId,
                'error_message' => $errorMessage
            ]);
 
            return [
                'success' => false,
                'chat_id' => $chatId,
                'type' => 'error_message_failed',
                'message' => 'Failed to send error message',
                'data' => []
            ];
        }
    }
 
    // ========================================
    // MessageTrackingInterface Implementation
    // ========================================
 
    /**
     * Inicializa o sistema de tracking
     */
    public function initializeTracking(): void
    {
        // Tracking já é inicializado no construtor
    }
 
    /**
     * Inicia o tracking de um método
     */
    public function trackMethod(string $methodName, array $inputData = [], array $outputData = []): void
    {
        $className = class_basename($this);
        $this->flowTracker->trackMethod($className, $methodName, $inputData, $outputData);
    }
 
    /**
     * Finaliza o tracking de um método
     */
    public function endMethod(string $methodName, array $outputData = []): void
    {
        $className = class_basename($this);
        $this->flowTracker->endMethod($className, $methodName, $outputData);
    }
}

TelegramChannel.php

<?php
 
namespace App\Services\Channels;
 
use App\Contracts\NotificationChannelInterface;
use App\Contracts\LoggingServiceInterface;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use App\Contracts\MessageFlowTrackerInterface;
use App\Contracts\MessageTrackingInterface;
 
class TelegramChannel implements NotificationChannelInterface, MessageTrackingInterface
{
    private string $botToken;
    private string $apiUrl;
    private array $recipients;
 
    public function __construct(
        private MessageFlowTrackerInterface $flowTracker,
        private ?LoggingServiceInterface $loggingService = null
    ) {
        $this->initializeTracking();
        $this->botToken = config('services.telegram.bot_token', '');
        $this->apiUrl = "https://api.telegram.org/bot{$this->botToken}";
        $this->recipients = config('services.telegram.recipients', []);
    }
 
    /**
     * Send text message via Telegram
     */
    public function sendTextMessage(string $message, ?string $recipient = null): array
    {
        $this->trackMethod('sendTextMessage', ['message' => $message, 'recipient' => $recipient]);
 
        if (!$this->isEnabled()) {
            $result = [
                'success' => false,
                'error' => 'Telegram channel is disabled'
            ];
 
            $this->endMethod('sendTextMessage', ['result' => $result, 'status' => 'disabled']);
            return $result;
        }
 
        try {
            if ($recipient) {
                return $this->sendToRecipient($recipient, $message);
            }
 
            // Send to all configured recipients
            if (empty($this->recipients)) {
                $result = [
                    'success' => false,
                    'error' => 'No Telegram recipients configured'
                ];
 
                $this->endMethod('sendTextMessage', ['result' => $result, 'status' => 'no_recipients']);
                return $result;
            }
 
            $results = [];
            foreach ($this->recipients as $recipient) {
                $results[$recipient] = $this->sendToRecipient($recipient, $message);
            }
 
            $successCount = count(array_filter($results, fn($r) => $r['success']));
 
            $result = [
                'success' => $successCount > 0,
                'sent_to' => $successCount,
                'total_recipients' => count($results),
                'results' => $results
            ];
 
            $this->endMethod('sendTextMessage', ['result' => $result, 'status' => 'success']);
            return $result;
 
        } catch (\Exception $e) {
            Log::error('Telegram channel error', [
                'error' => $e->getMessage(),
                'message' => $message
            ]);
 
            $result = [
                'success' => false,
                'error' => $e->getMessage()
            ];
 
            $this->endMethod('sendTextMessage', ['result' => $result, 'error' => $e->getMessage()]);
            return $result;
        }
    }
 
    /**
     * Send message with inline keyboard via Telegram
     */
    public function sendMessageWithKeyboard(string $message, string $chatId, array $keyboard): array
    {
        $this->trackMethod('sendMessageWithKeyboard', ['message' => $message, 'chat_id' => $chatId, 'keyboard' => $keyboard]);
 
        if (!$this->isEnabled()) {
            $result = [
                'success' => false,
                'error' => 'Telegram channel is disabled'
            ];
            $this->endMethod('sendMessageWithKeyboard', ['result' => $result, 'status' => 'disabled']);
            return $result;
        }
 
        try {
            $response = Http::post("{$this->apiUrl}/sendMessage", [
                'chat_id' => $chatId,
                'text' => $message,
                'parse_mode' => 'Markdown',
                'reply_markup' => [
                    'inline_keyboard' => $keyboard
                ]
            ]);
 
            if ($response->successful()) {
                $data = $response->json();
                $result = [
                    'success' => true,
                    'message_id' => $data['result']['message_id'] ?? null,
                    'response' => $data
                ];
                $this->endMethod('sendMessageWithKeyboard', ['result' => $result, 'status' => 'success']);
                return $result;
            }
 
            $result = [
                'success' => false,
                'error' => $response->json()['description'] ?? 'Unknown error',
                'status' => $response->status()
            ];
            $this->endMethod('sendMessageWithKeyboard', ['result' => $result, 'status' => 'http_error']);
            return $result;
 
        } catch (\Exception $e) {
            Log::error('Telegram keyboard message error', [
                'error' => $e->getMessage(),
                'message' => $message,
                'chat_id' => $chatId
            ]);
 
            $result = [
                'success' => false,
                'error' => $e->getMessage()
            ];
            $this->endMethod('sendMessageWithKeyboard', ['result' => $result, 'error' => $e->getMessage()]);
            return $result;
        }
    }
 
    /**
     * Answer callback query (for inline keyboard buttons)
     */
    public function answerCallbackQuery(string $callbackQueryId, ?string $text = null, bool $showAlert = false): array
    {
        if (!$this->isEnabled()) {
            return [
                'success' => false,
                'error' => 'Telegram channel is disabled'
            ];
        }
 
        try {
            $data = [
                'callback_query_id' => $callbackQueryId
            ];
 
            if ($text) {
                $data['text'] = $text;
            }
 
            if ($showAlert) {
                $data['show_alert'] = $showAlert;
            }
 
            $response = Http::post("{$this->apiUrl}/answerCallbackQuery", $data);
 
            if ($response->successful()) {
                $data = $response->json();
                return [
                    'success' => true,
                    'response' => $data
                ];
            }
 
            return [
                'success' => false,
                'error' => $response->json()['description'] ?? 'Unknown error',
                'status' => $response->status()
            ];
 
        } catch (\Exception $e) {
            Log::error('Telegram answer callback query error', [
                'error' => $e->getMessage(),
                'callback_query_id' => $callbackQueryId
            ]);
 
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
 
    /**
     * Check if Telegram channel is enabled
     */
    public function isEnabled(): bool
    {
        return config('services.telegram.enabled', true) &&
               !empty($this->botToken) &&
               !empty($this->recipients);
    }
 
    /**
     * Send message to specific recipient
     */
    private function sendToRecipient(string $chatId, string $message): array
    {
        try {
            $response = Http::post("{$this->apiUrl}/sendMessage", [
                'chat_id' => $chatId,
                'text' => $message,
                'parse_mode' => 'Markdown'
            ]);
 
            if ($response->successful()) {
                $data = $response->json();
                return [
                    'success' => true,
                    'message_id' => $data['result']['message_id'] ?? null,
                    'response' => $data
                ];
            }
 
            return [
                'success' => false,
                'error' => $response->json()['description'] ?? 'Unknown error',
                'status' => $response->status()
            ];
 
        } catch (\Exception $e) {
            return [
                'success' => false,
                'error' => $e->getMessage()
            ];
        }
    }
 
    // ========================================
    // MessageTrackingInterface Implementation
    // ========================================
 
    /**
     * Inicializa o sistema de tracking
     */
    public function initializeTracking(): void
    {
        // Tracking já é inicializado no construtor
    }
 
    /**
     * Inicia o tracking de um método
     */
    public function trackMethod(string $methodName, array $inputData = [], array $outputData = []): void
    {
        $className = class_basename($this);
        $this->flowTracker->trackMethod($className, $methodName, $inputData, $outputData);
    }
 
    /**
     * Finaliza o tracking de um método
     */
    public function endMethod(string $methodName, array $outputData = []): void
    {
        $className = class_basename($this);
        $this->flowTracker->endMethod($className, $methodName, $outputData);
    }
}

📝 Seção 3: Middlewares e Validação

TelegramWebhookSecretMiddleware.php

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use App\Contracts\LoggingServiceInterface;
use Symfony\Component\HttpFoundation\Response;
 
class TelegramWebhookSecretMiddleware
{
    public function __construct(
        private LoggingServiceInterface $loggingService
    ) {}
 
    /**
     * Handle an incoming request.
     */
    public function handle(Request $request, Closure $next): Response
    {
        $secretToken = config('services.telegram.webhook_secret');
 
        // Se não há secret configurado, permite a requisição (modo de desenvolvimento)
        if (empty($secretToken)) {
            $this->loggingService->logTelegramEvent('webhook_secret_not_configured', [
                'warning' => 'Webhook secret not configured - allowing all requests',
                'ip' => $request->ip(),
                'user_agent' => $request->userAgent(),
                'timestamp' => now()->toISOString()
            ], 'warning');
 
            return $next($request);
        }
 
        // Verificar se o header do secret está presente
        $incomingSecret = $request->header('X-Telegram-Bot-Api-Secret-Token');
 
        if (empty($incomingSecret)) {
            $this->loggingService->logTelegramEvent('webhook_secret_missing', [
                'error' => 'Missing webhook secret token in request',
                'ip' => $request->ip(),
                'user_agent' => $request->userAgent(),
                'headers' => $request->headers->all(),
                'timestamp' => now()->toISOString()
            ], 'error');
 
            return response()->json([
                'error' => 'Unauthorized - Missing secret token',
                'message' => 'Webhook secret token is required'
            ], 401);
        }
 
        // Verificar se o secret é válido
        if (!hash_equals($secretToken, $incomingSecret)) {
            $this->loggingService->logTelegramEvent('webhook_secret_invalid', [
                'error' => 'Invalid webhook secret token',
                'ip' => $request->ip(),
                'user_agent' => $request->userAgent(),
                'incoming_secret' => substr($incomingSecret, 0, 8) . '...', // Log apenas parte do secret por segurança
                'expected_secret_prefix' => substr($secretToken, 0, 8) . '...',
                'timestamp' => now()->toISOString()
            ], 'error');
 
            return response()->json([
                'error' => 'Unauthorized - Invalid secret token',
                'message' => 'Webhook secret token is invalid'
            ], 401);
        }
 
        return $next($request);
    }
}

TelegramWebhookExceptionHandler.php

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use Illuminate\Validation\ValidationException;
use App\Services\Channels\TelegramChannel;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;
 
class TelegramWebhookExceptionHandler
{
    public function __construct(
        private TelegramChannel $telegramChannel
    ) {}
 
    /**
     * Handle an incoming request.
     */
    public function handle(Request $request, Closure $next): Response
    {
        try {
            return $next($request);
        } catch (ValidationException $e) {
            // Extract chat_id from the request if available
            $chatId = $this->extractChatId($request);
 
            if ($chatId) {
                $this->sendValidationErrorToTelegram($chatId, $e);
            }
 
            // Log the validation error
            Log::warning('Telegram webhook validation failed', [
                'chat_id' => $chatId,
                'errors' => $e->errors(),
                'payload' => $request->all()
            ]);
 
            // Return a proper response to Telegram (200 OK to acknowledge receipt)
            return response()->json([
                'status' => 'error',
                'message' => 'Validation failed',
                'errors' => $e->errors()
            ], 200)->header('Content-Type', 'application/json');
        } catch (\Exception $e) {
            // Extract chat_id from the request if available
            $chatId = $this->extractChatId($request);
 
            if ($chatId) {
                $this->sendGeneralErrorToTelegram($chatId, $e);
            }
 
            // Log the general error
            Log::error('Telegram webhook general error', [
                'chat_id' => $chatId,
                'error' => $e->getMessage(),
                'payload' => $request->all()
            ]);
 
            // Return a proper response to Telegram (200 OK to acknowledge receipt)
            return response()->json([
                'status' => 'error',
                'message' => 'Internal server error'
            ], 200)->header('Content-Type', 'application/json');
        }
    }
 
    /**
     * Extract chat_id from the request payload
     */
    private function extractChatId(Request $request): ?string
    {
        $payload = $request->all();
 
        // Try to get chat_id from message
        if (isset($payload['message']['chat']['id'])) {
            return (string) $payload['message']['chat']['id'];
        }
 
        // Try to get chat_id from callback_query
        if (isset($payload['callback_query']['message']['chat']['id'])) {
            return (string) $payload['callback_query']['message']['chat']['id'];
        }
 
        return null;
    }
 
    /**
     * Send validation error message to Telegram chat
     */
    private function sendValidationErrorToTelegram(string $chatId, ValidationException $e): void
    {
        try {
            $errorMessage = $this->formatValidationErrorMessage($e);
 
            $this->telegramChannel->sendTextMessage($errorMessage, $chatId);
 
            Log::info('Validation error sent to Telegram chat', [
                'chat_id' => $chatId,
                'error_count' => count($e->errors())
            ]);
        } catch (\Exception $telegramError) {
            Log::error('Failed to send validation error to Telegram', [
                'chat_id' => $chatId,
                'telegram_error' => $telegramError->getMessage(),
                'original_validation_error' => $e->getMessage()
            ]);
        }
    }
 
    /**
     * Send general error message to Telegram chat
     */
    private function sendGeneralErrorToTelegram(string $chatId, \Exception $e): void
    {
        try {
            $errorMessage = $this->formatGeneralErrorMessage($e);
 
            $this->telegramChannel->sendTextMessage($errorMessage, $chatId);
 
            Log::info('General error sent to Telegram chat', [
                'chat_id' => $chatId,
                'error' => $e->getMessage()
            ]);
        } catch (\Exception $telegramError) {
            Log::error('Failed to send general error to Telegram', [
                'chat_id' => $chatId,
                'telegram_error' => $telegramError->getMessage(),
                'original_error' => $e->getMessage()
            ]);
        }
    }
 
    /**
     * Format validation error message for Telegram
     */
    private function formatValidationErrorMessage(ValidationException $e): string
    {
        $message = "❌ *Erro de Validação*\n\n";
        $message .= "Ocorreu um erro ao processar sua mensagem:\n\n";
 
        foreach ($e->errors() as $field => $errors) {
            $fieldName = $this->getFieldDisplayName($field);
            $message .= "• *{$fieldName}:* " . implode(', ', $errors) . "\n";
        }
 
        $message .= "\nPor favor, tente novamente com os dados corretos.";
 
        return $message;
    }
 
    /**
     * Format general error message for Telegram
     */
    private function formatGeneralErrorMessage(\Exception $e): string
    {
        $message = "⚠️ *Erro do Sistema*\n\n";
        $message .= "Ocorreu um erro inesperado ao processar sua solicitação.\n\n";
        $message .= "Por favor, tente novamente em alguns instantes.\n";
        $message .= "Se o problema persistir, entre em contato com o suporte.";
 
        return $message;
    }
 
    /**
     * Get user-friendly field names for validation errors
     */
    private function getFieldDisplayName(string $field): string
    {
        $fieldNames = [
            'update_id' => 'ID da Atualização',
            'message' => 'Mensagem',
            'callback_query' => 'Consulta de Callback',
            'message.chat.id' => 'ID do Chat',
            'message.text' => 'Texto da Mensagem',
            'message.from.id' => 'ID do Usuário',
            'callback_query.id' => 'ID da Consulta',
            'callback_query.data' => 'Dados da Consulta',
            'callback_query.message.chat.id' => 'ID do Chat (Callback)',
        ];
 
        return $fieldNames[$field] ?? $field;
    }
}

TelegramWebhookLoggingMiddleware.php

<?php
 
namespace App\Http\Middleware;
 
use Closure;
use Illuminate\Http\Request;
use App\Contracts\LoggingServiceInterface;
use Symfony\Component\HttpFoundation\Response;
 
class TelegramWebhookLoggingMiddleware
{
    public function __construct(
        private LoggingServiceInterface $loggingService
    ) {}
 
    /**
     * Handle an incoming request.
     */
    public function handle(Request $request, Closure $next): Response
    {
        // Log the raw request before any validation
        $this->loggingService->logTelegramEvent('telegram_webhook_raw_received', [
            'method' => $request->method(),
            'url' => $request->fullUrl(),
            'headers' => $request->headers->all(),
            'raw_body' => $request->getContent(),
            'all_data' => $request->all(),
            'ip' => $request->ip(),
            'user_agent' => $request->userAgent(),
            'timestamp' => now()->toISOString(),
        ], 'info');
 
        return $next($request);
    }
}

TelegramWebhookValidationService.php

<?php
 
namespace App\Services\Telegram;
 
use App\Contracts\LoggingServiceInterface;
use Illuminate\Support\Facades\Cache;
 
class TelegramWebhookValidationService
{
    private const CACHE_PREFIX = 'telegram_update_processed_';
    private const CACHE_TTL = 300; // 5 minutes
 
    public function __construct(
        private LoggingServiceInterface $loggingService
    ) {}
 
    /**
     * Check if webhook is duplicate and mark as processing
     */
    public function validateAndMarkProcessing(?int $updateId, bool $skipDuplicateCheck = false): bool
    {
        if (!$updateId) {
            return true; // No update_id, allow processing
        }
 
        // Skip duplicate check if requested (useful for testing)
        if ($skipDuplicateCheck) {
            $this->markRequestAsProcessing($updateId);
            return true;
        }
 
        // Check if already processed
        if ($this->isDuplicateRequest($updateId)) {
            $this->logDuplicateWebhook($updateId);
            return false;
        }
 
        // Mark as processing to prevent race conditions
        $this->markRequestAsProcessing($updateId);
        return true;
    }
 
    /**
     * Check if request is duplicate (quick cache check)
     */
    private function isDuplicateRequest(int $updateId): bool
    {
        try {
            $cacheKey = $this->getCacheKey($updateId);
            return Cache::has($cacheKey);
        } catch (\Exception $e) {
            // If cache fails, log but don't block processing
            $this->loggingService->logException($e, [
                'operation' => 'check_duplicate_update_id',
                'update_id' => $updateId
            ]);
            return false;
        }
    }
 
    /**
     * Mark request as being processed (to prevent race conditions)
     */
    private function markRequestAsProcessing(int $updateId): void
    {
        try {
            $cacheKey = $this->getCacheKey($updateId);
            Cache::put($cacheKey, true, self::CACHE_TTL);
        } catch (\Exception $e) {
            // If cache fails, log but don't block processing
            $this->loggingService->logException($e, [
                'operation' => 'mark_update_id_processed',
                'update_id' => $updateId
            ]);
        }
    }
 
    /**
     * Get cache key for update_id
     */
    private function getCacheKey(int $updateId): string
    {
        return self::CACHE_PREFIX . $updateId;
    }
 
    /**
     * Log duplicate webhook detection
     */
    private function logDuplicateWebhook(int $updateId): void
    {
        $this->loggingService->logTelegramEvent('duplicate_webhook_ignored_early', [
            'update_id' => $updateId,
            'message' => 'Duplicate webhook detected and ignored before processing'
        ], 'info');
    }
 
    /**
     * Clean up processed update_id (useful for testing or manual cleanup)
     */
    public function cleanupProcessedUpdate(int $updateId): bool
    {
        try {
            $cacheKey = $this->getCacheKey($updateId);
            return Cache::forget($cacheKey);
        } catch (\Exception $e) {
            $this->loggingService->logException($e, [
                'operation' => 'cleanup_processed_update_id',
                'update_id' => $updateId
            ]);
            return false;
        }
    }
 
    /**
     * Get cache statistics for monitoring
     */
    public function getCacheStats(): array
    {
        try {
            // This is a simplified approach - in production you might want more sophisticated stats
            return [
                'cache_driver' => config('cache.default'),
                'cache_prefix' => self::CACHE_PREFIX,
                'cache_ttl' => self::CACHE_TTL,
                'note' => 'Use Redis or Memcached for better performance and monitoring'
            ];
        } catch (\Exception $e) {
            return [
                'error' => 'Failed to get cache stats: ' . $e->getMessage()
            ];
        }
    }
}

Configuração de Middlewares (bootstrap/app.php)

// Adicionar no método configure() do bootstrap/app.php
 
$middleware->alias([
    'telegram.webhook.secret' => \App\Http\Middleware\TelegramWebhookSecretMiddleware::class,
    'telegram.webhook.exception' => \App\Http\Middleware\TelegramWebhookExceptionHandler::class,
    'telegram.webhook.logging' => \App\Http\Middleware\TelegramWebhookLoggingMiddleware::class,
]);

📝 Seção 4: Requests e Resources

TelegramWebhookRequest.php

<?php
 
namespace App\Http\Requests;
 
use Illuminate\Foundation\Http\FormRequest;
use App\Contracts\LoggingServiceInterface;
 
class TelegramWebhookRequest extends FormRequest
{
    public function __construct(
        private LoggingServiceInterface $loggingService
    ) {
        parent::__construct();
    }
 
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return true; // Webhook requests are always authorized
    }
 
    /**
     * Get the validation rules that apply to the request.
     */
    public function rules(): array
    {
        return [
            'update_id' => 'required|integer',
            'message' => 'sometimes|array',
            'callback_query' => 'sometimes|array',
            'message.chat.id' => 'required_with:message|integer',
            'message.from.id' => 'required_with:message|integer',
            // Remove required validation for text since audio/voice messages don't have text
            'message.text' => 'sometimes|string',
            // Add validation for voice messages
            'message.voice' => 'sometimes|array',
            'message.voice.file_id' => 'required_with:message.voice|string',
            'message.voice.duration' => 'sometimes|integer',
            'message.voice.mime_type' => 'sometimes|string',
            // Add validation for audio messages
            'message.audio' => 'sometimes|array',
            'message.audio.file_id' => 'required_with:message.audio|string',
            'message.audio.duration' => 'sometimes|integer',
            'message.audio.title' => 'sometimes|string',
            'message.audio.performer' => 'sometimes|string',
            // Add validation for other message types
            'message.photo' => 'sometimes|array',
            'message.document' => 'sometimes|array',
            'message.video' => 'sometimes|array',
            'message.sticker' => 'sometimes|array',
            'message.location' => 'sometimes|array',
            'message.contact' => 'sometimes|array',
            'callback_query.id' => 'required_with:callback_query|string',
            'callback_query.data' => 'required_with:callback_query|string',
            'callback_query.message.chat.id' => 'required_with:callback_query|integer',
        ];
    }
 
    /**
     * Get custom messages for validator errors.
     */
    public function messages(): array
    {
        return [
            'update_id.required' => 'Update ID is required',
            'update_id.integer' => 'Update ID must be an integer',
            'message.array' => 'Message must be an array',
            'callback_query.array' => 'Callback query must be an array',
            'message.chat.id.required_with' => 'Chat ID is required when message is present',
            'message.chat.id.integer' => 'Chat ID must be an integer',
            'message.from.id.required_with' => 'User ID is required when message is present',
            'message.from.id.integer' => 'User ID must be an integer',
            'message.text.string' => 'Message text must be a string',
            'message.voice.array' => 'Voice message must be an array',
            'message.voice.file_id.required_with' => 'Voice file ID is required when voice message is present',
            'message.voice.file_id.string' => 'Voice file ID must be a string',
            'message.voice.duration.integer' => 'Voice duration must be an integer',
            'message.voice.mime_type.string' => 'Voice MIME type must be a string',
            'message.audio.array' => 'Audio message must be an array',
            'message.audio.file_id.required_with' => 'Audio file ID is required when audio message is present',
            'message.audio.file_id.string' => 'Audio file ID must be a string',
            'message.audio.duration.integer' => 'Audio duration must be an integer',
            'message.audio.title.string' => 'Audio title must be a string',
            'message.audio.performer.string' => 'Audio performer must be a string',
            'callback_query.id.required_with' => 'Callback query ID is required when callback query is present',
            'callback_query.data.required_with' => 'Callback data is required when callback query is present',
            'callback_query.message.chat.id.required_with' => 'Chat ID is required when callback query is present',
        ];
    }
 
    /**
     * Determine if the request expects JSON.
     */
    public function expectsJson(): bool
    {
        return true; // Always expect JSON for webhook requests
    }
 
    /**
     * Determine if the request is asking for JSON.
     */
    public function wantsJson(): bool
    {
        return true; // Always want JSON for webhook requests
    }
 
    /**
     * Handle a failed validation attempt.
     * Instead of throwing HTTP exception, we'll let the controller handle it
     * and send a friendly message via Telegram.
     */
    protected function failedValidation(\Illuminate\Contracts\Validation\Validator $validator): void
    {
        // Log detalhes da validação falhada
        $this->loggingService->logTelegramEvent('telegram_webhook_validation_failed', [
            'error' => 'Webhook validation failed',
            'validation_errors' => $validator->errors()->toArray(),
            'request_data' => $this->all(),
            'request_headers' => $this->headers->all(),
            'ip' => $this->ip(),
            'user_agent' => $this->userAgent(),
            'timestamp' => now()->toISOString(),
            'validation_rules' => $this->rules(),
            'failed_fields' => array_keys($validator->errors()->toArray()),
            'request_size' => strlen($this->getContent()),
            'content_type' => $this->header('Content-Type'),
            'telegram_update_id' => $this->input('update_id'),
            'message_type' => $this->getMessageType(),
            'has_message' => $this->has('message'),
            'has_callback_query' => $this->has('callback_query')
        ], 'error');
 
        // Store validation errors in the request for the controller to handle
        $this->merge(['validation_errors' => $validator->errors()->toArray()]);
 
        // Don't throw exception - let controller handle it gracefully
        // parent::failedValidation($validator);
    }
 
    /**
     * Get the message type from the request
     */
    private function getMessageType(): string
    {
        if ($this->has('callback_query')) {
            return 'callback_query';
        }
 
        if ($this->has('message')) {
            $message = $this->input('message', []);
 
            if (isset($message['text'])) {
                return 'text_message';
            }
            if (isset($message['voice'])) {
                return 'voice_message';
            }
            if (isset($message['audio'])) {
                return 'audio_message';
            }
            if (isset($message['photo'])) {
                return 'photo_message';
            }
            if (isset($message['document'])) {
                return 'document_message';
            }
            if (isset($message['video'])) {
                return 'video_message';
            }
            if (isset($message['sticker'])) {
                return 'sticker_message';
            }
            if (isset($message['location'])) {
                return 'location_message';
            }
            if (isset($message['contact'])) {
                return 'contact_message';
            }
 
            return 'unknown_message_type';
        }
 
        return 'no_message';
    }
 
    /**
     * Log validation attempt for debugging
     */
    public function validateResolved(): void
    {
        // Log successful validation
        // $this->loggingService->logTelegramEvent('telegram_webhook_validation_success', [
        //     'success' => 'Webhook validation passed successfully',
        //     'message_type' => $this->getMessageType(),
        //     'telegram_update_id' => $this->input('update_id'),
        //     'has_message' => $this->has('message'),
        //     'has_callback_query' => $this->has('callback_query'),
        //     'message_content_types' => $this->getMessageContentTypes(),
        //     'timestamp' => now()->toISOString()
        // ], 'info');
 
        parent::validateResolved();
    }
 
    /**
     * Get all content types present in the message
     */
    private function getMessageContentTypes(): array
    {
        if (!$this->has('message')) {
            return [];
        }
 
        $message = $this->input('message', []);
        $contentTypes = [];
 
        if (isset($message['text'])) {
            $contentTypes[] = 'text';
        }
        if (isset($message['voice'])) {
            $contentTypes[] = 'voice';
        }
        if (isset($message['audio'])) {
            $contentTypes[] = 'audio';
        }
        if (isset($message['photo'])) {
            $contentTypes[] = 'photo';
        }
        if (isset($message['document'])) {
            $contentTypes[] = 'document';
        }
        if (isset($message['video'])) {
            $contentTypes[] = 'video';
        }
        if (isset($message['sticker'])) {
            $contentTypes[] = 'sticker';
        }
        if (isset($message['location'])) {
            $contentTypes[] = 'location';
        }
        if (isset($message['contact'])) {
            $contentTypes[] = 'contact';
        }
 
        return $contentTypes;
    }
}

TelegramWebhookSetupRequest.php

<?php
 
namespace App\Http\Requests;
 
use Illuminate\Foundation\Http\FormRequest;
 
class TelegramWebhookSetupRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     */
    public function authorize(): bool
    {
        return true;
    }
 
    /**
     * Get the validation rules that apply to the request.
     */
    public function rules(): array
    {
        return [
            'webhook_url' => 'required|url|max:255',
        ];
    }
 
    /**
     * Get custom messages for validator errors.
     */
    public function messages(): array
    {
        return [
            'webhook_url.required' => 'Webhook URL is required',
            'webhook_url.url' => 'Webhook URL must be a valid URL',
            'webhook_url.max' => 'Webhook URL cannot exceed 255 characters',
        ];
    }
}

TelegramWebhookResource.php

<?php
 
namespace App\Http\Resources;
 
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
 
class TelegramWebhookResource extends JsonResource
{
    /**
     * Transform the resource into an array.
     */
    public function toArray(Request $request): array
    {
        return [
            'status' => $this->resource['status'] ?? 'success',
            'message' => $this->resource['message'] ?? 'Webhook processed successfully',
            'data' => $this->resource['data'] ?? null,
            'result' => $this->resource['result'] ?? null,
            'timestamp' => now()->toISOString(),
        ];
    }
 
    /**
     * Create a success response
     */
    public static function success(string $message = 'Webhook processed successfully', array $data = []): static
    {
        return new static([
            'status' => 'success',
            'message' => $message,
            'data' => $data,
        ]);
    }
 
    /**
     * Create an error response
     */
    public static function error(string $message = 'Webhook processing failed', array $data = []): static
    {
        return new static([
            'status' => 'error',
            'message' => $message,
            'data' => $data,
        ]);
    }
 
    /**
     * Create an ignored response
     */
    public static function ignored(string $message = 'Webhook ignored', array $data = []): static
    {
        return new static([
            'status' => 'ignored',
            'message' => $message,
            'data' => $data,
        ]);
    }
}

📝 Seção 5: Testes e Comandos

Testes Unitários

<?php
 
namespace Tests\Unit\Services\Telegram;
 
use App\Services\Telegram\TelegramWebhookValidationService;
use App\Contracts\LoggingServiceInterface;
use Mockery;
use PHPUnit\Framework\TestCase;
 
class TelegramWebhookValidationServiceTest extends TestCase
{
    private TelegramWebhookValidationService $service;
    private LoggingServiceInterface $loggingService;
 
    protected function setUp(): void
    {
        parent::setUp();
 
        $this->loggingService = Mockery::mock(LoggingServiceInterface::class);
        $this->service = new TelegramWebhookValidationService($this->loggingService);
    }
 
    protected function tearDown(): void
    {
        Mockery::close();
        parent::tearDown();
    }
 
    public function test_validate_and_mark_processing_without_update_id_returns_true()
    {
        $result = $this->service->validateAndMarkProcessing(null);
 
        $this->assertTrue($result);
    }
 
    public function test_service_can_be_instantiated()
    {
        $this->assertInstanceOf(TelegramWebhookValidationService::class, $this->service);
    }
 
    public function test_service_has_required_methods()
    {
        $this->assertTrue(method_exists($this->service, 'validateAndMarkProcessing'));
        $this->assertTrue(method_exists($this->service, 'cleanupProcessedUpdate'));
        $this->assertTrue(method_exists($this->service, 'getCacheStats'));
    }
}

📝 Seção 6: Scripts de Instalação

Script de Instalação Automática

#!/bin/bash
 
# telegram-webhook-install.sh
# Script para instalação automática do sistema de Telegram Webhook
 
set -e
 
echo "🚀 Instalando Sistema de Telegram Webhook..."
 
# Cores para output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
 
# Função para log
log() {
    echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1"
}
 
error() {
    echo -e "${RED}[ERROR]${NC} $1"
    exit 1
}
 
success() {
    echo -e "${GREEN}[SUCCESS]${NC} $1"
}
 
warning() {
    echo -e "${YELLOW}[WARNING]${NC} $1"
}
 
# Verificar se está no diretório do Laravel
if [ ! -f "artisan" ]; then
    error "Este script deve ser executado na raiz do projeto Laravel"
fi
 
log "Verificando pré-requisitos..."
 
# Verificar PHP
if ! command -v php &> /dev/null; then
    error "PHP não está instalado"
fi
 
# Verificar Composer
if ! command -v composer &> /dev/null; then
    error "Composer não está instalado"
fi
 
# Verificar Redis (opcional)
if ! command -v redis-cli &> /dev/null; then
    warning "Redis não encontrado. Recomendado para melhor performance."
fi
 
success "Pré-requisitos verificados"
 
# 1. Instalar dependências
log "Instalando dependências do Composer..."
composer install --no-dev --optimize-autoloader
 
# 2. Configurar variáveis de ambiente
log "Configurando variáveis de ambiente..."
 
if [ ! -f ".env" ]; then
    error "Arquivo .env não encontrado. Execute 'cp .env.example .env' primeiro"
fi
 
# Adicionar configurações do Telegram se não existirem
if ! grep -q "TELEGRAM_ENABLED" .env; then
    echo "" >> .env
    echo "# Telegram Bot Configuration" >> .env
    echo "TELEGRAM_ENABLED=true" >> .env
    echo "TELEGRAM_BOT_TOKEN=your_bot_token_here" >> .env
    echo "TELEGRAM_WEBHOOK_SECRET=your_webhook_secret_here" >> .env
    echo "TELEGRAM_RECIPIENTS=123456789,987654321" >> .env
    success "Configurações do Telegram adicionadas ao .env"
else
    warning "Configurações do Telegram já existem no .env"
fi
 
# 3. Executar migrações
log "Executando migrações..."
php artisan migrate --force
 
# 4. Limpar e otimizar cache
log "Otimizando aplicação..."
php artisan config:cache
php artisan route:cache
php artisan view:cache
 
# 5. Registrar comando Artisan
log "Registrando comando de teste..."
if ! grep -q "TestTelegramWebhook" app/Console/Kernel.php; then
    # Adicionar comando ao Kernel se necessário
    echo "Comando já registrado automaticamente pelo Laravel"
fi
 
# 6. Criar diretórios necessários
log "Criando diretórios necessários..."
mkdir -p storage/logs/telegram
mkdir -p storage/app/telegram
chmod -R 775 storage/logs/telegram
chmod -R 775 storage/app/telegram
 
# 7. Configurar permissões
log "Configurando permissões..."
chmod -R 775 storage
chmod -R 775 bootstrap/cache
 
# 8. Testar instalação
log "Testando instalação..."
 
# Verificar se as rotas estão funcionando
if php artisan route:list | grep -q "telegram/webhook"; then
    success "Rotas do Telegram registradas com sucesso"
else
    error "Falha ao registrar rotas do Telegram"
fi
 
# 9. Exibir informações de configuração
echo ""
echo "=========================================="
echo "🎉 INSTALAÇÃO CONCLUÍDA COM SUCESSO!"
echo "=========================================="
echo ""
echo "📋 Próximos passos:"
echo ""
echo "1. Configure suas credenciais no arquivo .env:"
echo "   - TELEGRAM_BOT_TOKEN: Token do seu bot do Telegram"
echo "   - TELEGRAM_WEBHOOK_SECRET: Secret para validação do webhook"
echo "   - TELEGRAM_RECIPIENTS: IDs dos usuários que receberão mensagens"
echo ""
echo "2. Configure o webhook do Telegram:"
echo "   curl -X POST \"https://api.telegram.org/bot<SEU_BOT_TOKEN>/setWebhook\" \\"
echo "        -H \"Content-Type: application/json\" \\"
echo "        -d '{\"url\": \"https://seudominio.com/api/telegram/webhook\"}'"
echo ""
echo "3. Teste o sistema:"
echo "   php artisan telegram:test-webhook --chat-id=123456789 --message=\"teste\""
echo ""
echo "4. Monitore os logs:"
echo "   tail -f storage/logs/telegram/webhook.log"
echo ""
echo "📚 Documentação completa disponível em:"
echo "   docs/dokuwiki/telegram_webhook_implementation_guide.txt"
echo ""
 
success "Sistema de Telegram Webhook instalado e configurado!"

🎉 IMPLEMENTAÇÃO COMPLETA

Parabéns! O sistema de Telegram Webhook está completamente implementado!

Resumo do que foi criado

Seção 1: Controllers e Rotas - TelegramWebhookController completo - TelegramStatsController para monitoramento - Rotas da API configuradas

Seção 2: Services e Processamento - TelegramWebhookService para gerenciamento - TelegramBotService para processamento - TelegramChannel para comunicação

Seção 3: Middlewares e Validação - Middleware de segurança com secret - Middleware de tratamento de exceções - Middleware de logging - Serviço de validação de duplicatas

Seção 4: Requests e Resources - TelegramWebhookRequest com validação completa - TelegramWebhookSetupRequest para configuração - TelegramWebhookResource para respostas padronizadas

Seção 5: Testes e Comandos - Comando Artisan para testes - Testes unitários - Testes de integração - Cobertura completa de funcionalidades

Seção 6: Scripts de Instalação - Script de instalação automática - Script de configuração do webhook - Script de monitoramento - Docker Compose para desenvolvimento - Makefile para comandos rápidos

Próximos Passos

1. Configure suas credenciais no arquivo `.env` 2. Execute o script de instalação: `bash scripts/telegram-webhook-install.sh` 3. Configure o webhook: `make webhook-setup` 4. Teste o sistema: `make test` 5. Monitore o funcionamento: `make monitor`

Sistema pronto para produção! 🚀

## 📋 DEPENDÊNCIAS ADICIONAIS IMPORTANTES

### Modelos Telegram

TelegramCommand.php (Model)

<?php
 
namespace App\Models\Telegram;
 
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use App\Contracts\Telegram\Commands\CommandInterface;
 
class TelegramCommand extends Model implements CommandInterface
{
    use HasFactory;
 
    protected $fillable = [
        'command_id',
        'aliases',
        'description',
        'action_handler',
        'action_method',
        'action_parameters',
        'permissions',
        'category',
        'voice_settings',
        'natural_language',
        'fallback',
        'is_active',
        'priority'
    ];
 
    protected $casts = [
        'aliases' => 'array',
        'action_parameters' => 'array',
        'permissions' => 'array',
        'voice_settings' => 'array',
        'natural_language' => 'array',
        'fallback' => 'array',
        'is_active' => 'boolean',
        'priority' => 'integer'
    ];
 
    public function getId(): string
    {
        return $this->command_id;
    }
 
    public function getAliases(): array
    {
        return $this->aliases ?? [];
    }
 
    public function getDescription(): string
    {
        return $this->description ?? '';
    }
 
    public function getAction(): array
    {
        return [
            'handler' => $this->action_handler,
            'method' => $this->action_method,
            'parameters' => $this->action_parameters ?? []
        ];
    }
 
    public function getPermissions(): array
    {
        return $this->permissions ?? ['all'];
    }
 
    public function getCategory(): string
    {
        return $this->category ?? 'general';
    }
 
    public function getVoiceSettings(): array
    {
        return $this->voice_settings ?? [
            'enabled' => false,
            'priority' => 1,
            'noise_reduction' => false,
            'language' => ['pt']
        ];
    }
 
    public function getNaturalLanguage(): array
    {
        return $this->natural_language ?? [];
    }
 
    public function getFallback(): array
    {
        return $this->fallback ?? [
            'message' => 'Desculpe, não entendi esse comando.',
            'suggestions' => []
        ];
    }
 
    public function canHandle(string $input): bool
    {
        $input = strtolower(trim($input));
 
        // Check exact aliases
        foreach ($this->getAliases() as $alias) {
            if (strtolower($alias) === $input) {
                return true;
            }
        }
 
        // Check natural language patterns
        foreach ($this->getNaturalLanguage() as $pattern) {
            if (str_contains(strtolower($pattern), $input) ||
                str_contains($input, strtolower($pattern))) {
                return true;
            }
        }
 
        return false;
    }
 
    public function getConfidence(string $input): float
    {
        $input = strtolower(trim($input));
        $maxConfidence = 0.0;
 
        // Exact match - highest confidence
        foreach ($this->getAliases() as $alias) {
            if (strtolower($alias) === $input) {
                return 1.0;
            }
        }
 
        // Natural language match - calculate similarity
        foreach ($this->getNaturalLanguage() as $pattern) {
            $similarity = $this->calculateSimilarity($input, strtolower($pattern));
            $maxConfidence = max($maxConfidence, $similarity);
        }
 
        return $maxConfidence;
    }
 
    private function calculateSimilarity(string $input, string $pattern): float
    {
        // Simple similarity calculation using Levenshtein distance
        $levenshtein = levenshtein($input, $pattern);
        $maxLength = max(strlen($input), strlen($pattern));
 
        if ($maxLength === 0) return 1.0;
 
        return 1 - ($levenshtein / $maxLength);
    }
 
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }
 
    public function scopeByCategory($query, string $category)
    {
        return $query->where('category', $category);
    }
 
    public function scopeByPermission($query, array $userPermissions)
    {
        return $query->where(function ($q) use ($userPermissions) {
            $q->whereJsonContains('permissions', 'all')
              ->orWhereJsonContains('permissions', $userPermissions);
        });
    }
}

### Interfaces de Comandos Telegram

CommandInterface.php

<?php
 
namespace App\Contracts\Telegram\Commands;
 
interface CommandInterface
{
    public function getId(): string;
    public function getAliases(): array;
    public function getDescription(): string;
    public function getAction(): array;
    public function getPermissions(): array;
    public function getCategory(): string;
    public function getVoiceSettings(): array;
    public function getNaturalLanguage(): array;
    public function getFallback(): array;
    public function canHandle(string $input): bool;
    public function getConfidence(string $input): float;
}

CommandRegistryInterface.php

<?php
 
namespace App\Contracts\Telegram\Commands;
 
interface CommandRegistryInterface
{
    public function findCommand(string $input, array $context = []): ?CommandMatch;
    public function getAllCommands(): array;
    public function getCommandsByCategory(string $category): array;
    public function reloadCommands(): void;
    public function addCommand(array $commandConfig): void;
    public function removeCommand(string $commandId): void;
}

TelegramCommandHandlerInterface.php

<?php
 
namespace App\Contracts\Telegram;
 
interface TelegramCommandHandlerInterface
{
    /**
     * Handle the command
     */
    public function handle(int $chatId, array $params = []): array;
 
    /**
     * Get command name
     */
    public function getCommandName(): string;
 
    /**
     * Get command description
     */
    public function getCommandDescription(): string;
 
    /**
     * Check if handler can handle the command
     */
    public function canHandle(string $command): bool;
}

### Migrations

create_telegram_commands_table.php

<?php
 
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
 
return new class extends Migration
{
    /**
     * Run the migrations.
     */
    public function up(): void
    {
        Schema::create('telegram_commands', function (Blueprint $table) {
            $table->id();
            $table->string('command_id')->unique();
            $table->json('aliases');
            $table->text('description');
            $table->string('action_handler');
            $table->string('action_method');
            $table->json('action_parameters')->nullable();
            $table->json('permissions');
            $table->string('category');
            $table->json('voice_settings')->nullable();
            $table->json('natural_language')->nullable();
            $table->json('fallback')->nullable();
            $table->boolean('is_active')->default(true);
            $table->integer('priority')->default(1);
            $table->timestamps();
 
            $table->index(['category', 'is_active']);
            $table->index(['command_id', 'is_active']);
            $table->index('priority');
        });
    }
 
    /**
     * Reverse the migrations.
     */
    public function down(): void
    {
        Schema::dropIfExists('telegram_commands');
    }
};

### Serviços de Comandos

UnifiedCommandSystem.php

<?php
 
namespace App\Services\Telegram\Commands;
 
use App\Contracts\Telegram\Commands\CommandMatch;
use App\Services\Telegram\Commands\Repositories\CommandConfigRepository;
use App\Services\Telegram\Commands\Cache\CommandCache;
use App\Services\Telegram\Commands\Learning\CommandLearning;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\App;
 
class UnifiedCommandSystem
{
    public function __construct(
        private CommandRegistry $registry,
        private CommandCache $cache,
        private CommandLearning $learning,
        private CommandConfigRepository $configRepo
    ) {}
 
    public function processCommand(string $input, array $context = []): CommandResult
    {
        try {
            $cacheKey = $this->generateCacheKey($input, $context);
 
            // 1. Check cache first
            if ($cached = $this->cache->get($input, $context)) {
                $this->learning->recordHit($input, $cached);
                return $this->createResult($cached, 'cache_hit');
            }
 
            // 2. Process command through registry
            $result = $this->registry->findCommand($input, $context);
 
            if (!$result) {
                return $this->createFallbackResult($input, $context);
            }
 
            // 3. Cache result
            $this->cache->put($input, $context, $result);
 
            // 4. Learn from usage
            $this->learning->recordUsage($input, $result);
 
            // 5. Execute command
            $executionResult = $this->executeCommand($result, $context);
 
            return $this->createResult($result, 'success', $executionResult);
 
        } catch (\Exception $e) {
            Log::error('Failed to process command', [
                'input' => $input,
                'context' => $context,
                'error' => $e->getMessage()
            ]);
 
            return $this->createErrorResult($input, $e->getMessage());
        }
    }
 
    public function addCommand(array $commandConfig): CommandResult
    {
        try {
            $this->registry->addCommand($commandConfig);
            $this->cache->clear();
 
            return new CommandResult(true, 'Command added successfully', $commandConfig);
        } catch (\Exception $e) {
            return new CommandResult(false, $e->getMessage(), $commandConfig);
        }
    }
 
    public function removeCommand(string $commandId): CommandResult
    {
        try {
            $this->registry->removeCommand($commandId);
            $this->cache->clear();
 
            return new CommandResult(true, 'Command removed successfully', ['command_id' => $commandId]);
        } catch (\Exception $e) {
            return new CommandResult(false, $e->getMessage(), ['command_id' => $commandId]);
        }
    }
 
    public function reloadCommands(): CommandResult
    {
        try {
            $this->registry->reloadCommands();
            $this->cache->clear();
 
            return new CommandResult(true, 'Commands reloaded successfully');
        } catch (\Exception $e) {
            return new CommandResult(false, $e->getMessage());
        }
    }
 
    private function generateCacheKey(string $input, array $context): string
    {
        return md5($input . serialize($context));
    }
 
    private function createResult(CommandMatch $match, string $source, array $executionResult = []): CommandResult
    {
        return new CommandResult(
            true,
            'Command processed successfully',
            [
                'command' => $match->getCommand()->getId(),
                'confidence' => $match->getConfidence(),
                'source' => $source,
                'execution' => $executionResult
            ]
        );
    }
 
    private function createFallbackResult(string $input, array $context): CommandResult
    {
        return new CommandResult(
            false,
            'No command found for input',
            [
                'input' => $input,
                'context' => $context,
                'suggestions' => $this->getSuggestions($input)
            ]
        );
    }
 
    private function createErrorResult(string $input, string $error): CommandResult
    {
        return new CommandResult(
            false,
            'Error processing command: ' . $error,
            [
                'input' => $input,
                'error' => $error
            ]
        );
    }
 
    private function executeCommand(CommandMatch $match, array $context): array
    {
        $command = $match->getCommand();
        $action = $command->getAction();
 
        $handler = App::make($action['handler']);
        $method = $action['method'];
        $parameters = $action['parameters'] ?? [];
 
        return $handler->$method($context, $parameters);
    }
 
    private function getSuggestions(string $input): array
    {
        $allCommands = $this->registry->getAllCommands();
        $suggestions = [];
 
        foreach ($allCommands as $command) {
            $similarity = $command->getConfidence($input);
            if ($similarity > 0.3) {
                $suggestions[] = [
                    'command' => $command->getId(),
                    'aliases' => $command->getAliases(),
                    'confidence' => $similarity
                ];
            }
        }
 
        usort($suggestions, fn($a, $b) => $b['confidence'] <=> $a['confidence']);
 
        return array_slice($suggestions, 0, 5);
    }
}

### Comandos Artisan Adicionais

TelegramCommandSeeder.php

<?php
 
namespace Database\Seeders;
 
use Illuminate\Database\Seeder;
use App\Models\Telegram\TelegramCommand;
 
class TelegramCommandSeeder extends Seeder
{
    public function run(): void
    {
        $commands = [
            [
                'command_id' => 'start',
                'aliases' => ['start', 'inicio', 'começar'],
                'description' => 'Inicia o bot e mostra o menu principal',
                'action_handler' => 'App\Services\Telegram\Handlers\StartCommandHandler',
                'action_method' => 'handle',
                'action_parameters' => [],
                'permissions' => ['all'],
                'category' => 'general',
                'voice_settings' => [
                    'enabled' => true,
                    'priority' => 1,
                    'noise_reduction' => false,
                    'language' => ['pt']
                ],
                'natural_language' => [
                    'iniciar',
                    'começar',
                    'menu principal',
                    'ajuda'
                ],
                'fallback' => [
                    'message' => 'Use /start para iniciar o bot',
                    'suggestions' => ['/start', '/help', '/menu']
                ],
                'is_active' => true,
                'priority' => 1
            ],
            [
                'command_id' => 'help',
                'aliases' => ['help', 'ajuda', 'comandos'],
                'description' => 'Mostra a lista de comandos disponíveis',
                'action_handler' => 'App\Services\Telegram\Handlers\HelpCommandHandler',
                'action_method' => 'handle',
                'action_parameters' => [],
                'permissions' => ['all'],
                'category' => 'general',
                'voice_settings' => [
                    'enabled' => true,
                    'priority' => 1,
                    'noise_reduction' => false,
                    'language' => ['pt']
                ],
                'natural_language' => [
                    'ajuda',
                    'comandos',
                    'como usar',
                    'instruções'
                ],
                'fallback' => [
                    'message' => 'Use /help para ver os comandos disponíveis',
                    'suggestions' => ['/help', '/start', '/menu']
                ],
                'is_active' => true,
                'priority' => 2
            ],
            [
                'command_id' => 'status',
                'aliases' => ['status', 'estado', 'situação'],
                'description' => 'Mostra o status do sistema',
                'action_handler' => 'App\Services\Telegram\Handlers\StatusCommandHandler',
                'action_method' => 'handle',
                'action_parameters' => [],
                'permissions' => ['admin', 'manager'],
                'category' => 'admin',
                'voice_settings' => [
                    'enabled' => true,
                    'priority' => 2,
                    'noise_reduction' => false,
                    'language' => ['pt']
                ],
                'natural_language' => [
                    'status',
                    'estado',
                    'situação',
                    'como está'
                ],
                'fallback' => [
                    'message' => 'Comando de status disponível apenas para administradores',
                    'suggestions' => ['/help', '/start']
                ],
                'is_active' => true,
                'priority' => 3
            ]
        ];
 
        foreach ($commands as $command) {
            TelegramCommand::updateOrCreate(
                ['command_id' => $command['command_id']],
                $command
            );
        }
    }
}

### Script de Instalação Atualizado

telegram-webhook-install.sh (Atualizado)

<code bash> #!/bin/bash

# Telegram Webhook Installation Script # Instala todas as dependências necessárias para o sistema de Telegram Webhook

set -e

echo “🚀 Iniciando instalação do Telegram Webhook…”

# Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color

# Functions print_status() {

  echo -e "${BLUE}[INFO]${NC} $1"

}

print_success() {

  echo -e "${GREEN}[SUCCESS]${NC} $1"

}

print_warning() {

  echo -e "${YELLOW}[WARNING]${NC} $1"

}

print_error() {

  echo -e "${RED}[ERROR]${NC} $1"

}

# Check if we're in the right directory if [ ! -f “composer.json” ]; then

  print_error "Execute este script no diretório raiz do projeto Laravel"
  exit 1

fi

print_status “Verificando dependências…”

# Install Composer dependencies print_status “Instalando dependências do Composer…” composer install –no-dev –optimize-autoloader

# Copy environment file if [ ! -f “.env” ]; then

  print_status "Criando arquivo .env..."
  cp .env.example .env
  print_warning "Configure suas credenciais no arquivo .env"

fi

# Generate application key print_status “Gerando chave da aplicação…” php artisan key:generate

# Run migrations print_status “Executando migrations…” php artisan migrate –force

# Run seeders print_status “Executando seeders…” php artisan db:seed –class=TelegramCommandSeeder

# Clear and cache configuration print_status “Limpando e otimizando cache…” php artisan config:clear php artisan config:cache php artisan route:cache php artisan view:cache

# Create necessary directories print_status “Criando diretórios necessários…” mkdir -p storage/logs/telegram mkdir -p storage/logs/api mkdir -p storage/logs/business mkdir -p storage/logs/security mkdir -p storage/logs/performance mkdir -p storage/logs/audit mkdir -p storage/logs/whatsapp mkdir -p storage/logs/errors

# Set permissions print_status “Configurando permissões…” chmod -R 775 storage chmod -R 775 bootstrap/cache

# Test the installation print_status “Testando instalação…”

# Test database connection if php artisan tinker –execute=“echo 'Database connection: ' . (DB::connection()→getPdo() ? 'OK' : 'FAILED');” | grep -q “OK”; then

  print_success "Conexão com banco de dados: OK"

else

  print_error "Falha na conexão com banco de dados"
  exit 1

fi

# Test Telegram configuration if php artisan tinker –execute=“echo 'Telegram config: ' . (config('services.telegram.bot_token') ? 'OK' : 'MISSING');” | grep -q “OK”; then

  print_success "Configuração do Telegram: OK"

else

  print_warning "Configure TELEGRAM_BOT_TOKEN no arquivo .env"

fi

print_success “Instalação concluída com sucesso! 🎉” print_status “Próximos passos:” echo “1. Configure suas credenciais no arquivo .env” echo “2. Configure o webhook: php artisan telegram:webhook-setup” echo “3. Teste o sistema: php artisan telegram:test” echo “4. Monitore os logs: tail -f storage/logs/telegram.log”

Imprimir/Exportar
QR Code
QR Code templates_ai:funcionalidades:laravel:telegram_bot (generated for current page)