# Violações Arquiteturais (Baseado em Código)

Este documento lista **padrões encontrados** no repositório que se encaixam nas categorias solicitadas. Quando algo não é identificado, é marcado como **Não identificado no código**. Não há sugestões de refatoração aqui.

## Lógica de negócio dentro de Controllers

### 1) Transação + regra de exclusão + efeito em “servidor dos clientes”

Arquivo: `app/Http/Controllers/Resposta/RespostaController.php`

Trecho:

```php
// Inicia a transação
DB::beginTransaction();

try {
    // Envia palavra para servidor dos clientes
    $this->deleteBootResposta(\Auth()->user()->cliente_id, $resposta->id);

    $resposta->usuario_exclusao_id = \Auth()->user()->id;
    $resposta->save();
    $resposta->delete();

    DB::commit();
    return [ 'Resposta excluída com sucesso.' ];
} catch (\Exception $e) {
    DB::rollback();
    return \Response::json(['errors' =>['erros' => ['Erro ao atualizar servidor cliente.']] ],404);
}
```

### 2) Persistência + transformação do request + integração externa (cURL) no mesmo controller

Arquivo: `app/Http/Controllers/Webhook/WebhookController.php`

Trecho (persistência e iteração sobre `request->campos`):

```php
public function store(Request $request)
{
    if ($request->url_envio == '') {
        return response()->json(['errors' => ['errors' => ["Campo da URL não pode ser vazio."]]], 404);
    }

    $url_envio = $this->webhookConfig::select('url')->where('tipo', 1)->count();

    if ($url_envio > 0) {
        $this->webhookConfig->where('tipo', 1)->whereNotNull('url')
            ->update([
                'url'          => $request->url_envio,
                'usuario'      => $request->usuario,
                'senha'        => $request->senha,
                'autenticacao' => $request->autenticacao,
                'tipo'         => 1
            ]);
    } else {
        $this->webhookConfig->insertGetId([
            'created_at' => date('Y-m-d H:i:s'),
            'url'     => $request->url_envio,
            'usuario' => $request->usuario,
            'senha'   => $request->senha,
            'autenticacao' => $request->autenticacao,
            'tipo'    => 1
        ]);
    }

    foreach ($request->campos as $key => $value) {
        $chave = $key + 1;
        $this->updateFormulario($value, $chave);
    }

    return [$mensagem];
}
```

Trecho (integração externa em `testeWebhook`):

```php
public function testeWebhook(Request $request)
{
    $url_envio = $this->webhookConfig::select('url', 'autenticacao')
        ->where('tipo', 1)
        ->first();

    if (empty($url_envio['url'])) {
        return response()->json(['error' => "Campo da URL não pode ser vazio."], 422);
    }

    $autenticacao = json_decode($url_envio['autenticacao'], true);

    $api_key = $autenticacao['user'];
    $password = $autenticacao['password'];

    $post = $request->nome;

    $x = curl_init($url_envio['url']);

    curl_setopt_array($x, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_CONNECTTIMEOUT => 3,
        CURLOPT_TIMEOUT => 3,
        CURLOPT_POSTFIELDS => $post,
        CURLOPT_IPRESOLVE => CURL_IPRESOLVE_V4,
        CURLOPT_FOLLOWLOCATION => false,
        CURLOPT_HTTPHEADER => [
            'Content-Type: application/json',
            'Content-Length: ' . strlen($post),
            'charset: UTF-8',
        ],
    ]);
```

## Query direta no Controller

### 1) Relatórios com SQL inline e `DB::raw(...)`

Arquivo: `app/Http/Controllers/Relatorio/ReportsHelper.php`

Trecho:

```php
$transferencias = AtendimentoTransferencia::select(
    'atendimento2.id as id_atendimento',
    DB::raw('CASE WHEN atendimento2.canal_id = 10 THEN "Telefonia" WHEN atendimento2.canal_id = 3 THEN "WhatsApp" WHEN atendimento2.canal_id = 5 THEN "Email" WHEN atendimento2.canal_id = 9 THEN "Webchat" END  as canal'),
    DB::raw('ifnull(fila_de_atendimento2.nome,numero_whatsapp2.numero) as fila'),
    DB::raw('"Transferido" AS status'),
    DB::raw('CASE WHEN atendimento_transferencia.destino_atendente_id IS NOT NULL THEN CONCAT(\'Atendente: \', atendimento_transferencia.destino_atendente_id) WHEN atendimento_transferencia.destino_fila_id IS NOT NULL THEN (SELECT CONCAT(\'Fila: \',fila_de_atendimento.nome) FROM fila_de_atendimento WHERE fila_de_atendimento.id = atendimento_transferencia.destino_fila_id LIMIT 1) WHEN atendimento_transferencia.destino_contato_externo IS NOT NULL THEN atendimento_transferencia.destino_contato_externo END AS destino'),
    DB::raw('solicitacao_chat_whatsapp2.numero_cliente as telefone'),
    DB::raw('numero_whatsapp2.numero as numero_integracao'),
    'atendimento2.cliente_nome as cliente'
)
->join('atendimento AS atendimento2', 'atendimento2.id', '=', 'atendimento_transferencia.atendimento_id');
```

### 2) Transação no Controller

Arquivo: `app/Http/Controllers/Resposta/RespostaController.php`

Evidência:
- `DB::beginTransaction();`
- `DB::commit();`
- `DB::rollback();`

## Acesso direto a Model em Blade

**Não identificado no código.**

Não foram encontrados padrões típicos de query/model dentro de `resources/views` (por exemplo: `DB::`, `App\\Models`, `::where(`, `::select(`).

## Services acoplados a Request

### 1) Service usando helper global `request()` (acoplamento ao contexto HTTP)

Arquivo: `app/Services/Bot/CheckFlowService.php`

Trecho:

```php
$cliente_id_dashboard = (int) request()->route('token_whatsapp');
if ($cliente_id_dashboard > 0) {
    UpdateMonitoramentoHibridoJob::dispatch($cliente_id_dashboard, ["canais.whatsapp", "emAtendimento", "espera", "finalizados"])->onQueue('monitoramento_hibrido');
}
```

## Dependência circular (ou alto acoplamento entre camadas)

### 1) Service chamando Controllers diretamente

Arquivo: `app/Services/Bot/CheckFlowService.php`

Trecho:

```php
use App\Http\Controllers\Chatbot\GerenciamentoBotController;
use App\Http\Controllers\Chatbot\GerenciamentoChatController;

$controllers = [
    'api' => GerenciamentoBotController::class,
    'chat' => GerenciamentoChatController::class,
    'web' => GerenciamentoBotController::class
];

if (isset($methods[$type]) && isset($controllers[$channel])) {
    $method = $methods[$type];
    $controller = $controllers[$channel];

    Log::info(__METHOD__ . ' | RODANDO STEP: ' . $getCurrentStep['step'] . PHP_EOL);

    $controller = app($controller);
    
    $clientId = $data['client_id'] ?? null;
    if ($clientId) {
        $client = Cliente::where('cliente_id', $clientId)->first();
        $client->connect();

        $controller->setClientId($clientId);
    }
    
    return $controller->$method($atendimentoId, $getCurrentStep, $flux, $botArray, $data);
}
```

### 2) Services instanciando Controllers (`FuncoesController`)

Arquivos:
- `app/Services/Bot/FileUploadService.php`
- `app/Services/Atendimento/FilasServices.php`

Evidências:
- `FileUploadService` importa `App\Http\Controllers\Funcoes\FuncoesController` e instancia `new FuncoesController`
- `FilasServices` também importa `FuncoesController` e instancia `$this->funcoes = new FuncoesController`

## Falta de separação de responsabilidades

Com base nos trechos acima, o padrão encontrado é que classes que não seriam “de orquestração HTTP” ou “de persistência” frequentemente:
- orquestram regra de negócio,
- constroem queries/relatórios diretamente,
- e, em alguns casos, fazem integração externa (ex.: `curl_init` no `WebhookController`),
- ou dependem diretamente do contexto HTTP (`request()` no `CheckFlowService`),
- e chamam Controllers a partir de Services (`CheckFlowService`).

