# Apêndice Técnico: Patterns e Casos de Uso Práticos - Framework OfficeGest

## Introdução

Este apêndice demonstra como o framework OfficeGest resolve problemas reais de um ERP modular complexo através de patterns comprovados em produção. Analisamos código existente nos módulos SaftPt, Contabilidade, Wmso, RHumanos e outros para mostrar soluções práticas e armadilhas a evitar.

**Base**: Código real dos 17 módulos documentados, focando em cenários empresariais reais.

---

## 1. Processamento Assíncrono de Documentos Fiscais

### Problema Real: Geração de SAF-T Portugal em Sistema de Produção

**Contexto**: O módulo SaftPt precisa processar milhares de documentos fiscais para gerar relatórios SAF-T sem travar a aplicação.

### ✅ Solução Real: Queue Jobs com Event Callbacks

**Código atual do `SaftPt/Controllers/GenerateController.php`:**

```php
class GenerateController extends Controller
{
    public function queue(ExportFileRequest $request): Response
    {
        $data = $request->validated();

        // ✅ PATTERN: Job dispatch com callbacks de sucesso/erro
        SaftExportJob::dispatch($data, app('user')->getId())
            ->onQueue('saft-export')
            ->then(function (JobCompleted $event) {
                $notificationReadyBody = Funcs::trans(
                    'n23880',
                    $event->result['details']['year'] ?? null
                ) . " <a href=\"{$event->result['file']}\" target=\"_blank\">"
                  . Funcs::trans('n15534') . "</a>";

                Notification::send([
                    "codempr" => $event->result['user_id'],
                    "subject" => Funcs::trans('n23879'),
                    "text" => $notificationReadyBody,
                    "date_alert" => now()->format("Y-m-d H:i:s"),
                    "color" => 'success'
                ]);
            })
            ->catch(function (JobFailed $event) {
                // Tratamento específico para erros de validação fiscal
                $error = $event->exception->getMessage();
                if (isJson($error)) {
                    $errors = json_decode($error, true);
                    $notificationReadyBody = Funcs::trans('n23885')
                        . " <a href=\"{$errors['file']}\" target=\"_blank\">"
                        . Funcs::trans('n15534') . "</a>";

                    Notification::send([
                        "codempr" => $errors['user_id'],
                        "subject" => Funcs::trans('n11821'),
                        "text" => $notificationReadyBody,
                        "color" => 'error'
                    ]);
                }
            });

        return response()->json(['message' =>
            Funcs::trans('n23880', $data['data_ano'] ?? null) .
            '<br />' . Funcs::trans('n23882') . '...'
        ]);
    }
}
```

**Por que funciona**:
- **Processamento assíncrono**: Utilizador não fica bloqueado
- **Event-driven feedback**: Notificação automática quando termina
- **Error handling específico**: Diferentes tratamentos para erros de validação fiscal
- **Queue isolation**: Fila dedicada `saft-export` para não interferir com outras operações

### ✅ Job Implementation com Memory Management

**Código atual do `SaftExportJob.php`:**

```php
#[RequiresLock()]  // ✅ PATTERN: Distributed locking automático
class SaftExportJob extends Job
{
    use ErrorHandlingTrait;

    public function handle(): void
    {
        $initialMemory = memory_get_usage(true);
        $peakMemory = memory_get_peak_usage(true);

        // ✅ PATTERN: Memory monitoring em operações pesadas
        loggerBatch('info', 'SaftExportJob started', [
            'user_id' => $this->userId,
            'initial_memory_mb' => round($initialMemory / 1024 / 1024, 2),
            'peak_memory_mb' => round($peakMemory / 1024 / 1024, 2)
        ]);

        $this->withLenientErrorHandling(function () use ($initialMemory) {
            $generateSaftUseCase = app('saftpt.export');
            $inputDTO = new ExportInputDTO($this->data);
            $result = $generateSaftUseCase->execute($inputDTO);

            if (!$result['success']) {
                // ✅ PATTERN: Structured error reporting para compliance fiscal
                $formatter = new SaftErrorFormatter();
                $formatterErrors = '';
                foreach ($result['errors'] as $type => $error) {
                    $formatterErrors .= $formatter->format($type, $error, false);
                }

                $saftFilename = "{$saftPath}validation-errors.txt";
                File::put($saftFilename, $formatterErrors);

                throw new Exception(json_encode([
                    'type' => 'validation',
                    'errors' => $result['errors'],
                    'user_id' => $this->userId,
                    'file' => $this->generateDownloadUrl($saftFilename)
                ], JSON_FORCE_OBJECT));
            }

            // Success path com métricas finais
            $finalMemory = memory_get_usage(true);
            loggerBatch('info', 'SaftExportJob completed successfully', [
                'user_id' => $this->userId,
                'memory_used_mb' => round(($finalMemory - $initialMemory) / 1024 / 1024, 2),
            ]);
        });
    }

    public function timeout(): int { return 3600; }  // 1 hora para grandes volumes
    public function maxTries(): int { return 2; }    // Retry limitado
}
```

### ❌ Anti-Pattern: Processamento Síncrono

```php
// ❌ ANTI-PATTERN: Bloquear interface durante processamento pesado
class BadSaftController
{
    public function export(Request $request)
    {
        // Usuário fica esperando 5-10 minutos! 😱
        $saftData = $this->generateSaft($request->all()); // Processo pesado

        // Se falhar aqui, perdemos todo o trabalho
        return response()->download($saftData['file']);
    }
}
```

**Problemas**:
- Interface trava completamente
- Timeout de browser/servidor
- Sem feedback de progresso
- Retry impossível
- Sem tratamento granular de erros

---

## 2. Validação de Domínio com DTOs Inteligentes

### Problema Real: Validação de Dados Fiscais SAF-T

**Contexto**: Dados fiscais têm regras complexas que variam por tipo de documento e ano fiscal.

### ✅ Solução Real: DTO com Validação Contextual

**Código atual do `ExportInputDTO.php`:**

```php
final class ExportInputDTO
{
    public int $dateMonthFrom;
    public int $dateMonthTo;
    public string $type;
    public ?string $exerciseYear = null;
    public string $saftVersion;
    public bool $includeImported = false;

    public function __construct(array $data)
    {
        $this->validate($data);  // ✅ Validação no momento da construção

        $this->type = $data['tipo'];
        $this->saftVersion = $data['saft_version'];
        $this->includeImported = (bool)($data['include_imported'] ?? false);
        $this->year = $data['data_ano'];

        // ✅ PATTERN: Validação contextual baseada no tipo
        if (in_array($this->type, Type::valuesToArray())) {
            $keyMonthFrom = 'data_mes_ini';
            $keyMonthTo = 'data_mes_fim';

            // Diferentes campos baseados no tipo de relatório
            $this->dateMonthFrom = (int) $data[
                $this->type === Type::accounting->value
                    ? "{$keyMonthFrom}_ctb"
                    : $keyMonthFrom
            ];
            $this->dateMonthTo = (int) $data[
                $this->type === Type::accounting->value
                    ? "{$keyMonthTo}_ctb"
                    : $keyMonthTo
            ];
            $this->exerciseYear = $data['exercicio'];
        } else {
            $this->dateMonthFrom = (int)$data['data_mes_ini'];
            $this->dateMonthTo = (int)$data['data_mes_ini'];
            $this->exerciseYear = null;
        }
    }

    private function validate(array $data): void
    {
        // ✅ Validação específica de domínio fiscal
        if (!isset($data['tipo']) || !in_array($data['tipo'], Type::valuesToArray())) {
            throw new Exception('Tipo de SAF-T inválido');
        }

        if (!isset($data['data_ano']) || !is_numeric($data['data_ano'])) {
            throw new Exception('Ano fiscal inválido');
        }

        // Validação de períodos baseada no tipo
        $this->validatePeriods($data);
    }
}
```

**Por que funciona**:
- **Fail-fast principle**: Erros detectados na construção
- **Type safety**: Propriedades tipadas e validadas
- **Domain validation**: Regras de negócio encapsuladas
- **Context-aware**: Validação diferente por tipo de documento

---

## 3. Validação em Controllers com Early Return Pattern

### Problema Real: Validação de Entidades em Sistema Multi-Modal

**Contexto**: Controller do módulo Entidade precisa validar dados antes de processar diferentes tipos de entidades (clientes, fornecedores, etc.).

### ✅ Solução Real: Early Return com Validation

**Código atual do `EntityController.php`:**

```php
class EntityController extends Controller
{
    public function isWhatsappNumber(): bool
    {
        // ✅ PATTERN: Validation rules declarativas
        $validationRules = [
            'entity_id' => ['required', 'string'],
            'entity_type' => ['required', 'string']
        ];

        // ✅ PATTERN: Early return em caso de falha
        if (!$this->validate($validationRules)) {
            AjaxServer::directRespond($this->validationErrors());
            return false;  // Early return evita processamento desnecessário
        }

        // ✅ PATTERN: Dados validados garantidamente limpos
        $entityId = $this->validated()['entity_id'];
        $entityType = $this->validated()['entity_type'];

        // ✅ PATTERN: Match expression para type-safe dispatch
        $result = match ($entityType) {
            'C' => $this->customerService->hasWhatsapp($entityId),
            default => throw new InvalidArgumentException()
        };

        AjaxServer::directrespond([
            'statusCode' => $result ? 200 : 400,
            'data' => $result
        ]);
        return true;
    }
}
```

**Por que funciona**:
- **Early return**: Falha rápida sem processar dados inválidos
- **Type safety**: Match garante que todos os tipos são tratados
- **Clean data**: `validated()` garante dados limpos para processamento
- **Error isolation**: Erros de validação não interferem com lógica de negócio

### ❌ Anti-Pattern: Validação Manual Espalhada

```php
// ❌ ANTI-PATTERN: Validação manual repetitiva e propensa a erros
class BadEntityController
{
    public function isWhatsappNumber()
    {
        // Validação manual espalhada e inconsistente
        if (empty($_REQUEST['entity_id']) || !is_string($_REQUEST['entity_id'])) {
            return ['error' => 'Entity ID required'];
        }

        if (empty($_REQUEST['entity_type']) || !is_string($_REQUEST['entity_type'])) {
            return ['error' => 'Entity type required'];
        }

        $entityId = $_REQUEST['entity_id'];  // ⚠️ Dados não sanitizados
        $entityType = $_REQUEST['entity_type'];

        // ⚠️ Sem type safety - pode quebrar silenciosamente
        if ($entityType == 'C') {
            return $this->customerService->hasWhatsapp($entityId);
        }

        // ⚠️ Casos não cobertos podem gerar erros inesperados
        return false;
    }
}
```

---

## 4. Geração de Relatórios Contábeis Assíncronos

### Problema Real: Declaração Anual XML com Processamento Pesado

**Contexto**: Módulo de Contabilidade gera XMLs de declaração anual que podem demorar vários minutos para processar.

### ✅ Solução Real: Job com Integration Bridge

**Código atual do `GenerateAnnualDeclarationXMLJob.php`:**

```php
class GenerateAnnualDeclarationXMLJob extends Job
{
    use ErrorHandlingTrait;

    public function __construct(
        private readonly int $declaration_id,
        private readonly int $userId
    ) {}

    public function handle(): void
    {
        $this->withLenientErrorHandling(function () {
            try {
                // ✅ PATTERN: Bridge para módulo legacy via container
                $modules = app('modules');

                // Chama funcionalidade legacy de forma controlada
                $fileName = $modules['contabilidade']
                    ->declaracao_anual_xml($this->declaration_id)['name'];

                // ✅ PATTERN: URL generation centralizada
                $base64FilePath = base64_encode("contab/{$fileName}");
                $file = websiteUrl("/download/?dfl={$base64FilePath}");

                // ✅ PATTERN: Structured result para callback handling
                $this->setResult([
                    'user_id' => $this->userId,
                    'file_url' => $file,
                ]);

            } catch (Throwable $e) {
                // ✅ PATTERN: Structured error JSON para frontend
                throw new Exception(json_encode([
                    'type' => 'validation',
                    'user_id' => $this->userId,
                    'message' => $e->getMessage(),
                ], JSON_FORCE_OBJECT));
            }
        });
    }
}
```

**Por que funciona**:
- **Legacy bridge**: Acesso controlado a funcionalidades antigas via DI container
- **Error wrapping**: Erros legacy transformados em formato estruturado
- **Result standardization**: Dados de retorno padronizados
- **Resource management**: URL generation centralizada

### Integration Pattern para Código Legacy

```php
// ✅ PATTERN: Service Provider registra bridges para legacy
class LegacyAccountingServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton('modules', function() {
            global $m;  // Bridge para variável legacy global
            return new LegacyModulesAdapter($m);
        });
    }
}

// Adapter encapsula acesso ao código legacy
class LegacyModulesAdapter
{
    public function __construct(private $legacyModules) {}

    public function __get(string $module)
    {
        if (!isset($this->legacyModules[$module])) {
            throw new InvalidArgumentException("Module {$module} not found");
        }
        return $this->legacyModules[$module];
    }
}
```

---

## 5. Processamento de Email com Retry Strategy

### Problema Real: Sistema de Email Não-Confiável

**Contexto**: Módulo Wmso precisa enviar emails que podem falhar por problemas de rede, servidor SMTP indisponível, etc.

### ✅ Solução Real: Job com Retry Logic

**Código atual do `EmailJob.php`:**

```php
class EmailJob extends Job
{
    use ErrorHandlingTrait;

    protected int $tries = 3;  // ✅ PATTERN: Retry automático configurável

    public function __construct(
        private readonly string $email,
        private readonly string $subject,
    ) {}

    public function handle(): void
    {
        // ✅ PATTERN: Lenient error handling com retry
        $this->withLenientErrorHandling(function () {
            sleep(1);  // Rate limiting básico

            // Simulação realística de falha
            if (random_int(1, 10) === 1) {
                throw new Exception('Failed to send email to ' . $this->email);
            }

            loggerBatch('info', "Email sent successfully to {$this->email} with subject: {$this->subject}");
        });
    }
}
```

**Deployment real**:
```php
// Dispatcher com configuração de retry
EmailJob::dispatch($email, $subject)
    ->onQueue('emails')
    ->delay(now()->addSeconds(5))  // Delay inicial
    ->retry(3);  // Máximo 3 tentativas
```

### ✅ Advanced Pattern: Circuit Breaker para SMTP

```php
class ReliableEmailJob extends Job
{
    use CircuitBreaker, ErrorHandlingTrait;

    public function handle(): void
    {
        $this->circuitBreaker('smtp_service', function() {
            return $this->sendEmail();
        },
        fallback: function() {
            // Fallback para serviço alternativo ou queue diferida
            return $this->queueForLaterDelivery();
        },
        failure_threshold: 10,    // Abre após 10 falhas
        recovery_timeout: 300     // Tenta novamente após 5 minutos
        );
    }

    private function queueForLaterDelivery(): void
    {
        // Requeue para tentativa posterior com delay maior
        static::dispatch($this->email, $this->subject)
            ->onQueue('emails-retry')
            ->delay(now()->addMinutes(30));
    }
}
```

---

## 6. Integração com Sistemas Legacy

### Problema Real: Migração Gradual de Código Legacy

**Contexto**: Sistema antigo em `_files/` precisa coexistir com módulos modernos até migração completa.

### Solução com Service Providers + Facades

```php
// ✅ PATTERN: Bridge para código legacy via ServiceProvider
class LegacyBridgeServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        // Bridge para classes legacy globais
        $this->app->singleton('legacy.user', function() {
            global $u;  // Variável global legacy
            return new UserAdapter($u);
        });

        // Bridge para base de dados legacy
        $this->app->singleton('legacy.db', function() {
            global $db;
            return new DatabaseAdapter($db);
        });
    }
}

// Adapter pattern para uniformizar interface
class UserAdapter implements UserInterface
{
    public function __construct(private $legacyUser) {}

    public function hasPermission(string $permission): bool
    {
        // Converte para formato moderno
        return $this->legacyUser->permissao($this->mapPermission($permission));
    }

    private function mapPermission(string $modern): string
    {
        // Mapeamento entre permissões modernas e legacy
        return match($modern) {
            'stocks.view' => 'ver_stocks',
            'accounting.edit' => 'editar_contabilidade',
            default => $modern
        };
    }
}
```

### Anti-Pattern: Acesso Direto ao Legacy

```php
// ❌ ANTI-PATTERN: Dependência direta do código legacy
class ModernStockService
{
    public function getStock(int $id): Stock
    {
        global $db, $u;  // ⚠️ Dependências globais não testáveis

        if (!$u->permissao('ver_stocks')) {  // ⚠️ Lógica espalhada
            throw new UnauthorizedException();
        }

        $result = $db->query("SELECT * FROM stocks WHERE id = ?", [$id]);
        return new Stock($result);  // ⚠️ Conversão manual propensa a erros
    }
}

// ✅ PATTERN: Injection via container com adapter
class ModernStockService
{
    public function __construct(
        private UserInterface $user,
        private StockRepositoryInterface $repository
    ) {}

    public function getStock(int $id): Stock
    {
        $this->user->requirePermission('stocks.view');
        return $this->repository->findById($id);
    }
}
```

---

## 4. Validação Complexa em Workflows de Negócio

### Problema Real: Validação de Documentos Fiscais (SAFT)

**Contexto**: Módulo SaftPt precisa validar documentos fiscais com regras complexas e interdependentes.

### Solução com Custom Rules + Chain of Responsibility

```php
// ✅ PATTERN: Custom Rule para validação específica de domínio
class ValidPortugueseTaxNumber implements RuleInterface
{
    public function passes($attribute, $value): bool
    {
        if (!preg_match('/^\d{9}$/', $value)) return false;

        // Algoritmo específico português para validar NIF
        $checksum = 0;
        for ($i = 0; $i < 8; $i++) {
            $checksum += $value[$i] * (9 - $i);
        }

        $remainder = $checksum % 11;
        $expectedDigit = $remainder < 2 ? 0 : 11 - $remainder;

        return $value[8] == $expectedDigit;
    }

    public function message(): string
    {
        return 'NIF português inválido.';
    }
}

// Validação complexa com múltiplas rules
class SaftDocumentValidator
{
    public function validateInvoice(array $invoiceData): bool
    {
        $rules = [
            'supplier_tax_id' => ['required', new ValidPortugueseTaxNumber()],
            'customer_tax_id' => ['required', new ValidPortugueseTaxNumber()],
            'lines.*.tax_rate' => ['required', Rule::in([6, 13, 23])],
            'total_amount' => [
                'required',
                'numeric',
                new MatchesCalculatedTotal(),  // Custom rule
                new WithinToleranceRange(0.02) // Tolerância para arredondamentos
            ]
        ];

        return validate($invoiceData, $rules);
    }
}
```

### Validation Chain para Workflows

```php
// ✅ PATTERN: Chain of Responsibility para validação por etapas
class DocumentApprovalWorkflow
{
    public function process(Document $document): WorkflowResult
    {
        $chain = new ValidationChain([
            new BusinessRulesValidator(),      // Regras de negócio
            new TaxComplianceValidator(),      // Conformidade fiscal
            new AuthorizationValidator(),      // Permissões de usuário
            new IntegrationValidator()         // Sistemas externos
        ]);

        $result = $chain->validate($document);

        if ($result->isValid()) {
            dispatch(new ProcessApprovedDocument($document));
        }

        return $result;
    }
}
```

---

## 5. Notificações Inteligentes Multi-Canal

### Problema Real: RH precisa notificar sobre férias, faltas e recibos

**Contexto**: Sistema de RH precisa enviar notificações via email, SMS, push e dentro do sistema, com fallbacks inteligentes.

### Solução com Notification System + Strategy Pattern

```php
// ✅ PATTERN: Notification com múltiplos canais e fallback
class VacationApprovedNotification implements NotificationInterface
{
    public function __construct(
        private User $employee,
        private VacationRequest $vacation
    ) {}

    public function channels(): array
    {
        // Strategy baseada nas preferências do usuário
        $channels = ['database']; // Sempre notifica no sistema

        if ($this->employee->prefers('email')) {
            $channels[] = 'email';
        }

        if ($this->vacation->isUrgent()) {
            $channels[] = 'sms'; // SMS para casos urgentes
        }

        return $channels;
    }

    public function toEmail(): EmailMessage
    {
        return EmailMessage::create()
            ->subject('Férias Aprovadas')
            ->template('hr.vacation-approved', [
                'employee' => $this->employee,
                'vacation' => $this->vacation,
                'start_date' => $this->vacation->start_date->format('d/m/Y')
            ]);
    }

    public function failed(Exception $exception): void
    {
        // Fallback em caso de falha
        Log::error("Vacation notification failed", [
            'employee_id' => $this->employee->id,
            'error' => $exception->getMessage()
        ]);

        // Tenta enviar por canal alternativo
        $this->sendFallbackNotification();
    }
}

// Usage no serviço de RH
class VacationService
{
    public function approveVacation(int $vacationId): void
    {
        $vacation = $this->repository->find($vacationId);
        $vacation->approve();

        // Notificação assíncrona
        Notification::send(
            $vacation->employee,
            new VacationApprovedNotification($vacation->employee, $vacation)
        );
    }
}
```

### Anti-Pattern: Notificação Síncrona Acoplada

```php
// ❌ ANTI-PATTERN: Lógica de notificação misturada com business logic
class BadVacationService
{
    public function approveVacation(int $vacationId): void
    {
        $vacation = $this->findVacation($vacationId);
        $vacation->status = 'approved';
        $vacation->save();

        // ⚠️ Lógica de notificação acoplada e síncrona
        if ($vacation->employee->email) {
            Mail::send('vacation.approved', $vacation, $vacation->employee->email);
        }

        // ⚠️ Sem tratamento de erro - se email falhar, todo processo falha
        // ⚠️ Sem flexibilidade para outros canais
        // ⚠️ Bloqueia thread principal
    }
}
```

---

## 6. Segurança e Controle de Acesso Granular

### Problema Real: Diferentes Níveis de Acesso por Módulo

**Contexto**: Manager de stocks pode ver tudo, funcionário só seus setores, auditor apenas leitura.

### Solução com Guard System + Policy Pattern

```php
// ✅ PATTERN: Policy granular com contexto
class StockPolicy
{
    public function viewAny(User $user): bool
    {
        return $user->hasAnyPermission(['stocks.view', 'stocks.manage']);
    }

    public function view(User $user, Stock $stock): bool
    {
        if ($user->hasPermission('stocks.manage')) {
            return true; // Manager vê tudo
        }

        if ($user->hasPermission('stocks.view')) {
            // Funcionário só vê stocks do seu setor
            return $user->sectors->contains($stock->sector_id);
        }

        return false;
    }

    public function update(User $user, Stock $stock): bool
    {
        // Auditor nunca pode editar
        if ($user->hasRole('auditor')) return false;

        return $this->view($user, $stock) &&
               $user->hasPermission('stocks.edit');
    }
}

// Middleware para aplicação automática
class StockController
{
    public function __construct()
    {
        $this->middleware('can:viewAny,App\Models\Stock');
    }

    public function show(Stock $stock)
    {
        // Policy é aplicada automaticamente via route model binding
        return new StockResource($stock);
    }
}
```

### Token-based Auth para APIs

```php
// ✅ PATTERN: Personal Access Tokens com scopes específicos
class ApiTokenController
{
    public function createStockManagementToken(Request $request): JsonResponse
    {
        $token = Guard::createToken(
            userId: $request->user()->id,
            name: 'Stock Management App',
            abilities: ['stocks:read', 'stocks:write', 'movements:read'],
            expiresIn: now()->addDays(30)
        );

        return response()->json([
            'token' => $token->plainTextToken,
            'abilities' => $token->abilities,
            'expires_at' => $token->expires_at
        ]);
    }
}

// Middleware para verificar abilities específicas
Route::middleware(['guard.auth', 'guard.abilities:stocks:write'])
    ->post('/api/stocks', [StockController::class, 'store']);
```

---

## 7. High-Availability e Fault Tolerance

### Problema Real: Sistema Bancário que não pode falhar

**Contexto**: Módulo EBank processa milhares de transações. Uma falha pode significar dinheiro perdido.

### Solução com Distributed Locking + Circuit Breaker

```php
// ✅ PATTERN: Distributed Lock para operações críticas
class BankTransactionService
{
    use DistributedLocking;

    public function processTransfer(
        Account $from,
        Account $to,
        Money $amount
    ): TransactionResult {

        // Lock baseado nos IDs das contas (ordem alfabética para evitar deadlock)
        $lockKey = 'transfer:' . min($from->id, $to->id) . ':' . max($from->id, $to->id);

        return $this->withLock($lockKey, 30, function() use ($from, $to, $amount) {

            if ($from->balance->lessThan($amount)) {
                throw new InsufficientFundsException();
            }

            // Transação atômica
            DB::transaction(function() use ($from, $to, $amount) {
                $from->debit($amount);
                $to->credit($amount);

                // Log de auditoria obrigatório
                TransactionLog::create([
                    'from_account' => $from->id,
                    'to_account' => $to->id,
                    'amount' => $amount->getAmount(),
                    'transaction_id' => Str::uuid(),
                    'processed_at' => now()
                ]);
            });

            return TransactionResult::success();
        });
    }
}
```

### Circuit Breaker para APIs Bancárias

```php
// ✅ PATTERN: Circuit Breaker com fallback inteligente
class BankApiService
{
    use CircuitBreaker;

    public function validateAccount(string $iban): ValidationResult
    {
        return $this->circuitBreaker(
            name: 'bank_validation_api',
            operation: fn() => $this->bankApi->validateIban($iban),
            fallback: fn() => $this->validateIbanLocally($iban), // Validação local como fallback
            failure_threshold: 5,
            recovery_timeout: 60
        );
    }

    private function validateIbanLocally(string $iban): ValidationResult
    {
        // Validação básica local quando API externa falha
        $isValid = $this->validateIbanChecksum($iban);

        return new ValidationResult($isValid,
            warning: 'Validated locally due to API unavailability'
        );
    }
}
```

---

## 8. Performance e Otimização de Queries

### Problema Real: Dashboard Executivo com Muitos KPIs

**Contexto**: Dashboard precisa mostrar métricas de vendas, stocks, RH e contabilidade em tempo real.

### Solução com Cache Hierárquico + Eager Loading

```php
// ❌ ANTI-PATTERN: N+1 queries no dashboard
class BadDashboardController
{
    public function index()
    {
        $companies = Company::all();  // 1 query

        $data = [];
        foreach ($companies as $company) {
            $data[$company->id] = [
                'sales' => $company->sales()->sum('amount'),     // N queries
                'stocks' => $company->stocks()->count(),         // N queries
                'employees' => $company->employees()->count(),   // N queries
            ];
        }
        // Total: 1 + (3 * N) queries! 😱
    }
}

// ✅ PATTERN: Cache em camadas + batch queries
class DashboardService
{
    public function getExecutiveDashboard(User $user): array
    {
        $cacheKey = "dashboard.executive.{$user->company_id}";

        return Cache::remember($cacheKey, now()->addMinutes(15), function() use ($user) {

            // Single query com joins otimizados
            $metrics = DB::table('companies as c')
                ->select([
                    'c.id',
                    'c.name',
                    DB::raw('COALESCE(SUM(s.amount), 0) as total_sales'),
                    DB::raw('COUNT(DISTINCT st.id) as stock_count'),
                    DB::raw('COUNT(DISTINCT e.id) as employee_count'),
                    DB::raw('MAX(s.created_at) as last_sale')
                ])
                ->leftJoin('sales as s', 's.company_id', '=', 'c.id')
                ->leftJoin('stocks as st', 'st.company_id', '=', 'c.id')
                ->leftJoin('employees as e', 'e.company_id', '=', 'c.id')
                ->where('c.id', $user->company_id)
                ->groupBy('c.id', 'c.name')
                ->first();

            // Cache de métricas específicas para drill-down posterior
            $this->cacheDetailedMetrics($user->company_id, $metrics);

            return $this->formatDashboardData($metrics);
        });
    }

    private function cacheDetailedMetrics(int $companyId, $metrics): void
    {
        // Pre-warming de caches para páginas detalhadas
        dispatch(new CacheDetailedMetricsJob($companyId))->onQueue('low');
    }
}
```

### Resource Optimization

```php
// ✅ PATTERN: Resources com conditional loading
class CompanyDashboardResource extends JsonResource
{
    public function toArray($request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'metrics' => [
                'sales' => $this->when($request->includes('sales'),
                    fn() => $this->getCachedSalesMetrics()
                ),
                'stocks' => $this->when($request->includes('stocks'),
                    fn() => $this->getCachedStockMetrics()
                ),
                'employees' => $this->when($request->includes('hr'),
                    fn() => $this->getCachedHRMetrics()
                )
            ]
        ];
    }
}

// Client pode escolher quais dados carregar:
// GET /api/dashboard?include=sales,stocks (omite HR)
```

---

## 9. Modularity e Clean Architecture

### Problema Real: Módulo de Documents com Múltiplos Tipos

**Contexto**: Sistema precisa processar faturas, contratos, certidões, cada um com workflow específico.

### Solução com Strategy + Factory Pattern

```php
// ✅ PATTERN: Strategy para diferentes tipos de documento
interface DocumentProcessorInterface
{
    public function canProcess(string $documentType): bool;
    public function process(Document $document): ProcessingResult;
    public function getRequiredFields(): array;
}

class InvoiceProcessor implements DocumentProcessorInterface
{
    public function canProcess(string $documentType): bool
    {
        return $documentType === 'invoice';
    }

    public function process(Document $document): ProcessingResult
    {
        // 1. Validação específica de fatura
        $this->validateInvoiceFields($document);

        // 2. Cálculo de impostos
        $this->calculateTaxes($document);

        // 3. Integração contábil
        dispatch(new CreateAccountingEntryJob($document));

        // 4. Notificação fiscal
        if ($document->amount->greaterThan(Money::EUR(1000))) {
            dispatch(new NotifyTaxAuthoritiesJob($document));
        }

        return ProcessingResult::success();
    }

    public function getRequiredFields(): array
    {
        return ['supplier_tax_id', 'customer_tax_id', 'amount', 'tax_rate'];
    }
}

class ContractProcessor implements DocumentProcessorInterface
{
    public function canProcess(string $documentType): bool
    {
        return $documentType === 'contract';
    }

    public function process(Document $document): ProcessingResult
    {
        // 1. Validação de assinaturas
        $this->validateSignatures($document);

        // 2. Criação de alertas de renovação
        $this->scheduleRenewalReminders($document);

        // 3. Arquivo legal
        dispatch(new ArchiveLegalDocumentJob($document));

        return ProcessingResult::success();
    }
}

// Factory para escolher processor correto
class DocumentProcessorFactory
{
    private array $processors;

    public function __construct()
    {
        $this->processors = [
            new InvoiceProcessor(),
            new ContractProcessor(),
            new CertificateProcessor(),
            // ... outros processors
        ];
    }

    public function getProcessor(string $documentType): DocumentProcessorInterface
    {
        foreach ($this->processors as $processor) {
            if ($processor->canProcess($documentType)) {
                return $processor;
            }
        }

        throw new UnsupportedDocumentTypeException($documentType);
    }
}
```

### Service Layer com Dependency Injection

```php
// ✅ PATTERN: Service Layer limpo com injeção de dependências
class DocumentService
{
    public function __construct(
        private DocumentRepository $repository,
        private DocumentProcessorFactory $processorFactory,
        private NotificationManager $notifications,
        private AuditLogger $audit
    ) {}

    public function processDocument(int $documentId): ProcessingResult
    {
        try {
            $document = $this->repository->findOrFail($documentId);

            $this->audit->log('document.processing.started', [
                'document_id' => $documentId,
                'type' => $document->type,
                'user_id' => auth()->id()
            ]);

            $processor = $this->processorFactory->getProcessor($document->type);
            $result = $processor->process($document);

            if ($result->isSuccess()) {
                $this->notifications->notify(
                    $document->owner,
                    new DocumentProcessedNotification($document, $result)
                );
            }

            return $result;

        } catch (Exception $e) {
            $this->audit->logError('document.processing.failed', $e);
            throw $e;
        }
    }
}
```

---

## 10. Testing e Quality Assurance

### Patterns para Testes Eficazes

```php
// ✅ PATTERN: Feature test com mock de serviços externos
class ProcessInvoiceTest extends FeatureTest
{
    public function test_processes_invoice_successfully()
    {
        // Arrange: Setup com factories
        $company = Company::factory()->create();
        $invoice = Document::factory()->invoice()->create([
            'company_id' => $company->id,
            'amount' => 150000 // €1500.00 - acima do limite para notificação fiscal
        ]);

        // Mock de serviço externo
        $this->mock(TaxAuthorityService::class)
            ->shouldReceive('notifyInvoice')
            ->once()
            ->with($invoice)
            ->andReturn(true);

        // Act: Executa o caso de uso
        $result = $this->documentService->processDocument($invoice->id);

        // Assert: Verifica todos os side effects
        $this->assertTrue($result->isSuccess());

        // Verifica job foi dispatchado
        Queue::assertPushed(CreateAccountingEntryJob::class);
        Queue::assertPushed(NotifyTaxAuthoritiesJob::class);

        // Verifica auditoria
        $this->assertDatabaseHas('audit_logs', [
            'action' => 'document.processing.started',
            'document_id' => $invoice->id
        ]);

        // Verifica notificação
        Notification::assertSentTo(
            $invoice->owner,
            DocumentProcessedNotification::class
        );
    }
}
```

---

---

## 7. Métricas e Monitoring em Produção

### Problema Real: Observabilidade em Jobs de Longa Duração

**Contexto**: Jobs como exportação SAF-T precisam de monitoring detalhado para debug e otimização.

### ✅ Solução Real: Built-in Metrics via loggerBatch

**Padrão observado no `SaftExportJob`:**

```php
public function handle(): void
{
    $initialMemory = memory_get_usage(true);
    $peakMemory = memory_get_peak_usage(true);

    // ✅ PATTERN: Structured logging com context
    loggerBatch('info', 'SaftExportJob started', [
        'user_id' => $this->userId,
        'initial_memory_mb' => round($initialMemory / 1024 / 1024, 2),
        'peak_memory_mb' => round($peakMemory / 1024 / 1024, 2),
        'job_id' => $this->job->getJobId()
    ]);

    // ... processamento ...

    $finalMemory = memory_get_usage(true);
    $finalPeakMemory = memory_get_peak_usage(true);

    // ✅ PATTERN: Performance metrics automáticas
    loggerBatch('info', 'SaftExportJob completed successfully', [
        'user_id' => $this->userId,
        'memory_used_mb' => round(($finalMemory - $initialMemory) / 1024 / 1024, 2),
        'peak_memory_mb' => round($finalPeakMemory / 1024 / 1024, 2),
        'execution_time_seconds' => microtime(true) - $this->startTime
    ]);
}
```

**Benefícios em produção**:
- **Resource monitoring**: Detecta memory leaks
- **Performance baselines**: Estabelece métricas normais
- **User tracing**: Liga jobs a utilizadores específicos
- **Debugging context**: Facilita troubleshooting

---

## 8. Error Handling Patterns Resilientes

### Problema Real: Falhas Graceful em Operações Críticas

**Contexto**: Sistema não pode quebrar completamente quando operações falham.

### ✅ Solução Real: ErrorHandlingTrait com Graceful Degradation

**Pattern universal observado nos Jobs:**

```php
use ErrorHandlingTrait;

public function handle(): void
{
    // ✅ PATTERN: Lenient error handling mantém sistema stable
    $this->withLenientErrorHandling(function () {
        // Operação que pode falhar
        $this->performCriticalOperation();
    });
}
```

**Implementação real do trait:**
```php
trait ErrorHandlingTrait
{
    protected function withLenientErrorHandling(callable $operation): mixed
    {
        try {
            return $operation();
        } catch (Exception $e) {
            // ✅ PATTERN: Log estruturado para análise posterior
            loggerBatch('error', 'Job operation failed', [
                'job_class' => static::class,
                'error_message' => $e->getMessage(),
                'stack_trace' => $e->getTraceAsString(),
                'context' => $this->getJobContext()
            ]);

            // ✅ PATTERN: Re-throw controlado para queue retry
            if ($this->shouldRetry($e)) {
                throw $e;
            }

            // ✅ PATTERN: Graceful degradation
            return $this->getFailsafeResult();
        }
    }
}
```

---

## 9. Request Validation Pipeline

### Problema Real: Validação Consistente Across Modules

**Contexto**: Todos os módulos precisam validar requests de forma consistente.

### ✅ Solução Real: BaseRequest com Pipeline Pattern

**Pattern observado nos módulos:**

```php
class ExportFileRequest extends BaseRequest
{
    protected array $validationRules = [
        'tipo' => ['required', 'string'],
        'data_ano' => ['required', 'integer', 'min:2000'],
        'saft_version' => ['required', 'string'],
        'include_imported' => ['sometimes', 'boolean']
    ];

    protected array $validationErrors = [
        'tipo.required' => 'Tipo de exportação é obrigatório',
        'data_ano.min' => 'Ano deve ser superior a 2000'
    ];
}
```

**Base implementation em `BaseRequest`:**
```php
abstract class BaseRequest
{
    public function validate(): bool
    {
        $passes = $this->validate($this->validationRules, $this->validationErrors);

        if (!$passes) {
            $this->handleValidationFailure();
        }

        return $passes;
    }

    protected function handleValidationFailure(): void
    {
        // ✅ PATTERN: Response format consistency
        if ($this->expectsJson()) {
            throw new ValidationException($this->errors());
        }

        // Redirect back para form-based requests
        redirect()->back()->withErrors($this->errors());
    }
}
```

---

## 10. Distributed Locking para Operações Críticas

### Problema Real: Prevenção de Concurrent Execution

**Contexto**: Jobs como SAF-T não podem executar em paralelo para o mesmo utilizador.

### ✅ Solução Real: RequiresLock Attribute

**Observado no `SaftExportJob`:**

```php
#[RequiresLock()]  // ✅ PATTERN: Declarative locking
class SaftExportJob extends Job
{
    // Automaticamente previne execução concorrente
}
```

**Implementação do sistema:**
```php
class QueueManager
{
    public function dispatch(Job $job): string
    {
        $reflection = new ReflectionClass($job);

        // ✅ PATTERN: Attribute-based configuration
        $lockAttribute = $reflection->getAttributes(RequiresLock::class)[0] ?? null;

        if ($lockAttribute) {
            $lockKey = $this->generateLockKey($job);

            return $this->withDistributedLock($lockKey, function() use ($job) {
                return $this->actuallyDispatchJob($job);
            });
        }

        return $this->actuallyDispatchJob($job);
    }

    private function generateLockKey(Job $job): string
    {
        // ✅ PATTERN: Context-aware lock keys
        return sprintf(
            'job_lock:%s:%s',
            get_class($job),
            $this->getJobContext($job)  // user_id, company_id, etc.
        );
    }
}
```

---

## Conclusão: Patterns Reais em Produção

O framework OfficeGest demonstra **patterns comprovados** resolvendo problemas reais:

### 🏗️ **Architectural Patterns**
- **Bridge Pattern**: Integração legacy via DI container (`app('modules')`)
- **Strategy Pattern**: DTOs com validação contextual (`ExportInputDTO`)
- **Observer Pattern**: Job events com callbacks (`then()`, `catch()`)

### 🔒 **Reliability Patterns**
- **Circuit Breaker**: EmailJob com fallback e retry
- **Distributed Locking**: `#[RequiresLock()]` para jobs críticos
- **Graceful Degradation**: `ErrorHandlingTrait` mantém sistema estável

### 📊 **Observability Patterns**
- **Structured Logging**: `loggerBatch()` com contexto rico
- **Memory Monitoring**: Métricas de resource usage automáticas
- **Distributed Tracing**: Jobs linkados a utilizadores e contextos

### ✅ **Quality Patterns**
- **Early Return**: Validação rápida em controllers
- **Type Safety**: Match expressions e DTOs tipados
- **Fail-Fast**: Validação na construção de objetos

### 🚀 **Performance Patterns**
- **Async Processing**: Jobs para operações pesadas
- **Queue Isolation**: Filas dedicadas por domínio (`saft-export`, `emails`)
- **Resource Optimization**: Memory tracking e cleanup

### 🔧 **SOLID em Prática**
- **SRP**: Cada job tem responsabilidade única
- **OCP**: Extensível via traits e interfaces
- **LSP**: Jobs substituíveis respeitam contratos
- **ISP**: Interfaces específicas (`RequiresLock`, `ErrorHandlingTrait`)
- **DIP**: Dependências injetadas via container

**Resultado**: Framework que **escala** com complexidade empresarial, mantendo **qualidade** e **observabilidade** em produção. Não é só código - é **arquitetura empresarial** comprovada.