# Guia de Implementação - NF-e API

## Índice
1. [Visão Geral](#visão-geral)
2. [Arquitetura do Sistema](#arquitetura-do-sistema)
3. [Estrutura de Diretórios](#estrutura-de-diretórios)
4. [Componentes Principais](#componentes-principais)
5. [Fluxo de Dados](#fluxo-de-dados)
6. [Como Implementar em Outro Projeto](#como-implementar-em-outro-projeto)
7. [Padrões e Boas Práticas](#padrões-e-boas-práticas)
8. [Troubleshooting](#troubleshooting)

---

## Visão Geral

Este guia fornece instruções detalhadas para entender, adaptar e implementar a arquitetura da NF-e API em outros projetos.

### Princípios de Design

1. **Stateless**: Nenhum dado é persistido entre requisições
2. **Separation of Concerns**: Camadas bem definidas (HTTP, Controller, Service, Parser)
3. **Dependency Injection**: Injeção manual de dependências no Bootstrap
4. **Error Handling Centralizado**: Todas as exceções são tratadas no Router
5. **Data-Driven**: Mapeamento dinâmico de JSON para XML via NfeParser

---

## Arquitetura do Sistema

```
┌─────────────────────────────────────────────────────────────┐
│                     public/index.php                        │
│                  (Front Controller)                         │
│  - Captura exceções globais                                 │
│  - Envia resposta HTTP                                      │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│                    Bootstrap.php                            │
│              (Composition Root)                             │
│  - Instancia serviços                                       │
│  - Registra rotas                                           │
│  - Retorna Router configurado                               │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│                   Http/Router.php                           │
│            (Dispatcher + Error Boundary)                    │
│  - Mapeia rotas para handlers                               │
│  - Try/catch centralizado                                   │
│  - Converte exceções em JSON padronizado                    │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│                  Controller Layer                           │
│  - PreviaController                                         │
│  - EmissaoController                                        │
│  - CancelamentoController                                   │
│  - CartaCorrecaoController                                  │
│  - DanfeController                                          │
│  - DistDFeController                                        │
│                                                             │
│  Responsabilidade: Orquestração HTTP                        │
│  - Extrai dados do Request                                  │
│  - Valida presença de campos obrigatórios                   │
│  - Chama Service                                            │
│  - Retorna Response                                         │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│                   Service Layer                             │
│  - PreviaService                                            │
│  - EmissaoService                                           │
│  - EventService                                             │
│  - DanfeService                                             │
│  - DistDFeService                                           │
│                                                             │
│  Responsabilidade: Lógica de Negócio                        │
│  - Orquestra Parser, ToolsFactory, SEFAZ                    │
│  - Valida regras de negócio                                 │
│  - Trata respostas da SEFAZ                                 │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│                   Support Layer                             │
│  - NfeParser: JSON → NFePHP\NFe\Make                        │
│  - ToolsFactory: Config → NFePHP\NFe\Tools                  │
│  - SefazComm: Comunicação com SEFAZ + retry                 │
│  - DanfeRenderer: XML → PDF                                 │
└─────────────────────────────────────────────────────────────┘
```

---

## Estrutura de Diretórios

```
nfe_api/
├── public/
│   └── index.php              # Front controller (entry point)
│
├── src/
│   ├── Bootstrap.php          # Composition root
│   │
│   ├── Http/                  # Camada HTTP
│   │   ├── Request.php        # Wrapper do request HTTP
│   │   ├── Response.php       # Wrapper da response HTTP
│   │   └── Router.php         # Roteador + error boundary
│   │
│   ├── Controller/            # Controllers (orquestração HTTP)
│   │   ├── AbstractController.php
│   │   ├── PreviaController.php
│   │   ├── EmissaoController.php
│   │   ├── CancelamentoController.php
│   │   ├── CartaCorrecaoController.php
│   │   ├── DanfeController.php
│   │   └── DistDFeController.php
│   │
│   ├── Service/               # Services (lógica de negócio)
│   │   ├── PreviaService.php
│   │   ├── EmissaoService.php
│   │   ├── EventService.php
│   │   ├── DanfeService.php
│   │   └── DistDFeService.php
│   │
│   ├── Parser/                # Conversão de dados
│   │   └── NfeParser.php      # JSON → NFePHP\NFe\Make
│   │
│   ├── Config/                # DTOs de configuração
│   │   └── CertificateConfig.php
│   │
│   ├── Support/               # Utilitários
│   │   ├── ToolsFactory.php   # Factory para NFePHP\NFe\Tools
│   │   ├── SefazComm.php      # Comunicação com SEFAZ
│   │   └── DanfeRenderer.php  # Renderização de DANFE
│   │
│   └── Exception/             # Exceções customizadas
│       ├── ApiException.php
│       ├── ValidationException.php
│       ├── SefazRejectionException.php
│       └── SefazUnavailableException.php
│
├── tests/                     # Testes unitários
├── composer.json              # Dependências
└── README.md                  # Documentação básica
```

---

## Componentes Principais

### 1. Front Controller (`public/index.php`)

**Responsabilidade**: Ponto de entrada único da aplicação.

```php
<?php
require dirname(__DIR__) . '/vendor/autoload.php';

try {
    $router = Bootstrap::router();
    $response = $router->dispatch(Request::fromGlobals());
} catch (ApiException $e) {
    $response = Response::json([
        'success' => false,
        'error' => [
            'code' => $e->errorCode(),
            'message' => $e->getMessage(),
            'details' => $e->details()
        ]
    ], $e->statusCode());
} catch (Throwable $e) {
    $response = Response::json([
        'success' => false,
        'error' => [
            'code' => 'bootstrap_error',
            'message' => 'Falha ao inicializar a aplicacao.'
        ]
    ], 500);
}

$response->send();
```

**Conceitos-chave**:
- Captura exceções que ocorrem antes do Router
- Garante que sempre há uma resposta HTTP válida
- Não contém lógica de negócio

---

### 2. Bootstrap (`src/Bootstrap.php`)

**Responsabilidade**: Composition root - instancia e conecta todos os componentes.

```php
final class Bootstrap
{
    public static function router(): Router
    {
        // Instancia dependências
        $toolsFactory = new ToolsFactory();
        $parser = new NfeParser();
        $danfeRenderer = new DanfeRenderer();

        // Instancia services
        $previaService = new PreviaService($parser, $toolsFactory, $danfeRenderer);
        $emissaoService = new EmissaoService($parser, $toolsFactory);
        // ... outros services

        // Configura rotas
        $router = new Router();
        $router->get('/health', fn() => Response::json(['status' => 'ok']));
        $router->post('/nfe/previa', new PreviaController($previaService));
        $router->post('/nfe/emitir', new EmissaoController($emissaoService));
        // ... outras rotas

        return $router;
    }
}
```

**Conceitos-chave**:
- Único lugar onde `new` é chamado
- Grafo de dependências explícito
- Sem container de DI (simplicidade)

---

### 3. Router (`src/Http/Router.php`)

**Responsabilidade**: Roteamento + tratamento centralizado de erros.

```php
final class Router
{
    private array $routes = [];

    public function post(string $path, callable $handler): void
    {
        $this->routes['POST']['/' . trim($path, '/')] = $handler;
    }

    public function dispatch(Request $request): Response
    {
        try {
            $handler = $this->routes[$request->method][$request->path] ?? null;
            
            if ($handler === null) {
                return $this->error(404, 'not_found', 'Rota nao encontrada.');
            }

            return $handler($request);
        } catch (ApiException $e) {
            return $this->renderApiException($e);
        } catch (Throwable $e) {
            return $this->renderUnexpected($e);
        }
    }

    private function error(int $status, string $code, string $message, array $details = []): Response
    {
        $payload = [
            'success' => false,
            'error' => [
                'code' => $code,
                'message' => $message,
            ],
        ];

        if ($details !== []) {
            $payload['error']['details'] = $details;
        }

        return Response::json($payload, $status);
    }
}
```

**Conceitos-chave**:
- **Boundary único**: Todo handler executa dentro de um try/catch
- Converte exceções em respostas JSON padronizadas
- Mapeia exceções específicas para códigos HTTP corretos

---

### 4. Controllers

**Responsabilidade**: Orquestração HTTP - extrair dados, chamar service, retornar response.

```php
final class EmissaoController extends AbstractController
{
    public function __construct(private readonly EmissaoService $service) {}

    public function __invoke(Request $request): Response
    {
        // 1. Extrai e valida dados do request
        $config = $this->config($request);
        $payload = $this->requireArray($request, 'payload');
        $tributacao = is_array($request->input('tributacao')) 
            ? $request->input('tributacao') 
            : [];

        // 2. Chama o service
        $result = $this->service->handle($payload, $tributacao, $config);

        // 3. Retorna response padronizada
        return Response::json([
            'success' => true,
            'data' => $result,
        ]);
    }
}
```

**Conceitos-chave**:
- Não contém lógica de negócio
- Apenas validação de presença (não de conteúdo)
- Delega toda lógica para Services

---

### 5. Services

**Responsabilidade**: Lógica de negócio - orquestrar Parser, Tools, SEFAZ.

```php
final class EmissaoService
{
    public function __construct(
        private readonly NfeParser $parser,
        private readonly ToolsFactory $toolsFactory
    ) {}

    public function handle(array $payload, array $tributacao, CertificateConfig $config, array $options = []): array
    {
        // 1. Cria Tools com certificado
        $tools = $this->toolsFactory->make($config);

        // 2. Converte JSON em XML via Parser
        $make = $this->parser->build($payload, $tributacao, $config->schemes);
        $xml = $make->render();
        $chave = $make->getChave();

        // 3. Assina XML
        $signedXml = $tools->signNFe($xml);

        // 4. Envia para SEFAZ
        $loteResponse = SefazComm::send(
            fn() => $tools->sefazEnviaLote([$signedXml], $idLote, $indSinc)
        );

        // 5. Processa resposta
        $loteStd = SefazComm::toStd($loteResponse);
        // ... validações de cStat

        // 6. Monta nfeProc
        $nfeProc = Complements::toAuthorize($signedXml, $protocolXml);

        // 7. Retorna resultado
        return [
            'status' => 'autorizado',
            'chave' => $chave,
            'protocolo' => $nProt,
            'xml' => base64_encode($nfeProc),
            // ...
        ];
    }
}
```

**Conceitos-chave**:
- Orquestra múltiplas dependências
- Valida regras de negócio (cStat, etc.)
- Lança exceções específicas (ValidationException, SefazRejectionException)

---

### 6. NfeParser (`src/Parser/NfeParser.php`)

**Responsabilidade**: Converter JSON em objeto `NFePHP\NFe\Make`.

```php
final class NfeParser
{
    private const ITEM_TAX_MAP = [
        'icms' => 'tagICMS',
        'icmssn' => 'tagICMSSN',
        'ipi' => 'tagIPI',
        'pis' => 'tagPIS',
        'cofins' => 'tagCOFINS',
        'ibscbs' => 'tagIBSCBS',
        'is' => 'tagIS',
        // ...
    ];

    public function build(array $payload, array $tributacao = [], ?string $schema = null): Make
    {
        $make = new Make($schema);

        // Monta cabeçalho
        $make->taginfNFe($this->std($payload['infNFe'] ?? ['versao' => '4.00']));
        $make->tagide($this->std($payload['ide']));
        
        // Emitente
        $make->tagemit($this->std($payload['emit']));
        $make->tagenderEmit($this->std($payload['enderEmit']));

        // Destinatário
        if (isset($payload['dest'])) {
            $make->tagdest($this->std($payload['dest']));
        }

        // Itens
        foreach ($payload['det'] as $index => $item) {
            $this->buildItem($make, $item, $tributacao, $index + 1);
        }

        // Totais, transporte, pagamento
        $this->buildTotals($make, $payload);
        $this->buildTransport($make, $payload);
        $this->buildPayment($make, $payload);

        return $make;
    }

    private function buildItem(Make $make, array $item, array $tributacao, int $n): void
    {
        $make->tagprod($this->std($item['prod'], ['item' => $n]));
        $make->tagimposto($this->std($item['imposto'] ?? [], ['item' => $n]));

        // Despacha dinamicamente cada bloco tributário
        foreach (self::ITEM_TAX_MAP as $key => $method) {
            $block = $this->resolveTaxBlock($item, $tributacao, $key);
            if ($block !== null) {
                $make->{$method}($this->std($block, ['item' => $n]));
            }
        }
    }

    private function resolveTaxBlock(array $item, array $tributacao, string $key): ?array
    {
        // Item level wins, fallback to shared tributacao
        return $item[$key] ?? $tributacao[$key] ?? null;
    }
}
```

**Conceitos-chave**:
- **Data-driven**: Mapeamento dinâmico de blocos JSON para métodos Make
- **Fallback tributário**: Item pode herdar tributação padrão
- **Extensível**: Adicionar novo imposto = adicionar entrada no ITEM_TAX_MAP

---

### 7. Exceções Customizadas

```php
abstract class ApiException extends Exception
{
    abstract public function statusCode(): int;
    abstract public function errorCode(): string;
    public function details(): array { return []; }
}

class ValidationException extends ApiException
{
    public function statusCode(): int { return 400; }
    public function errorCode(): string { return 'validation_error'; }
}

class SefazRejectionException extends ApiException
{
    public function __construct(
        string $message,
        private readonly string $cStat,
        private readonly string $xMotivo,
        array $details = []
    ) {
        parent::__construct($message);
        $this->details = array_merge(['cStat' => $cStat, 'xMotivo' => $xMotivo], $details);
    }

    public function statusCode(): int { return 422; }
    public function errorCode(): string { return 'sefaz_rejection'; }
}

class SefazUnavailableException extends ApiException
{
    public function statusCode(): int { return 502; }
    public function errorCode(): string { return 'sefaz_unavailable'; }
}
```

**Conceitos-chave**:
- Hierarquia de exceções com status HTTP e código de erro
- Detalhes estruturados (cStat, xMotivo)
- Capturadas e convertidas pelo Router

---

## Fluxo de Dados

### Fluxo de Emissão de NF-e

```
1. Cliente HTTP
   ↓ POST /nfe/emitir + JSON
   
2. public/index.php
   ↓ Request::fromGlobals()
   
3. Bootstrap::router()
   ↓ Router configurado
   
4. Router::dispatch()
   ↓ Encontra EmissaoController
   ↓ try { handler($request) }
   
5. EmissaoController::__invoke()
   ↓ Extrai: config, payload, tributacao
   ↓ $service->handle(...)
   
6. EmissaoService::handle()
   ↓ $tools = ToolsFactory::make($config)
   ↓ $make = NfeParser::build($payload, $tributacao)
   ↓ $xml = $make->render()
   ↓ $signedXml = $tools->signNFe($xml)
   ↓ $response = SefazComm::send(fn() => $tools->sefazEnviaLote(...))
   ↓ Valida cStat
   ↓ $nfeProc = Complements::toAuthorize(...)
   ↓ return ['chave' => ..., 'xml' => base64_encode($nfeProc), ...]
   
7. EmissaoController
   ↓ return Response::json(['success' => true, 'data' => $result])
   
8. Router::dispatch()
   ↓ catch (ApiException) → renderApiException()
   ↓ return Response
   
9. public/index.php
   ↓ $response->send()
   
10. Cliente HTTP
    ← JSON response
```

---

## Como Implementar em Outro Projeto

### Cenário 1: Integrar como Microserviço

**Opção A: Docker**

```dockerfile
FROM php:8.2-cli

RUN apt-get update && apt-get install -y \
    libxml2-dev \
    libcurl4-openssl-dev \
    libzip-dev \
    zlib1g-dev \
    libpng-dev

RUN docker-php-ext-install soap curl dom simplexml mbstring zip gd

WORKDIR /app
COPY . /app

RUN composer install --no-dev --optimize-autoloader

EXPOSE 8080
CMD ["php", "-S", "0.0.0.0:8080", "-t", "public"]
```

```yaml
# docker-compose.yml
version: '3.8'
services:
  nfe-api:
    build: .
    ports:
      - "8080:8080"
    environment:
      - PHP_MEMORY_LIMIT=512M
```

**Opção B: Deploy em servidor**

```bash
# Instalar dependências
composer install --no-dev --optimize-autoloader

# Configurar Nginx
server {
    listen 80;
    server_name nfe-api.exemplo.com;
    root /var/www/nfe-api/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}
```

---

### Cenário 2: Integrar como Biblioteca em Projeto Existente

**Passo 1: Adicionar ao composer.json**

```json
{
  "require": {
    "diegoliermann/nfe-api": "^1.0"
  },
  "repositories": [
    {
      "type": "vcs",
      "url": "https://github.com/diegoliermann/nfe-api"
    }
  ]
}
```

**Passo 2: Usar componentes diretamente**

```php
use App\Parser\NfeParser;
use App\Service\EmissaoService;
use App\Support\ToolsFactory;
use App\Config\CertificateConfig;

// Instanciar dependências
$parser = new NfeParser();
$toolsFactory = new ToolsFactory();
$service = new EmissaoService($parser, $toolsFactory);

// Preparar config
$config = new CertificateConfig(
    certificado: base64_encode(file_get_contents('certificado.pfx')),
    senha: 'senha123',
    cnpj: '99999999000191',
    tpAmb: 2,
    uf: 'SP'
);

// Emitir NF-e
$result = $service->handle($payload, $tributacao, $config);

echo "Chave: " . $result['chave'];
echo "XML: " . base64_decode($result['xml']);
```

---

### Cenário 3: Adaptar para Framework (Laravel, Symfony)

**Laravel - Service Provider**

```php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use App\Parser\NfeParser;
use App\Service\EmissaoService;
use App\Support\ToolsFactory;

class NfeServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app->singleton(NfeParser::class);
        $this->app->singleton(ToolsFactory::class);
        
        $this->app->singleton(EmissaoService::class, function ($app) {
            return new EmissaoService(
                $app->make(NfeParser::class),
                $app->make(ToolsFactory::class)
            );
        });
    }
}
```

**Laravel - Controller**

```php
namespace App\Http\Controllers;

use App\Service\EmissaoService;
use App\Config\CertificateConfig;
use Illuminate\Http\Request;

class NfeController extends Controller
{
    public function __construct(private EmissaoService $service) {}

    public function emitir(Request $request)
    {
        $validated = $request->validate([
            'config' => 'required|array',
            'payload' => 'required|array',
            'tributacao' => 'array',
        ]);

        $config = new CertificateConfig(...$validated['config']);
        
        $result = $this->service->handle(
            $validated['payload'],
            $validated['tributacao'] ?? [],
            $config
        );

        return response()->json([
            'success' => true,
            'data' => $result
        ]);
    }
}
```

---

### Cenário 4: Criar Cliente HTTP (Consumir a API)

**PHP - Guzzle**

```php
use GuzzleHttp\Client;

class NfeApiClient
{
    private Client $client;

    public function __construct(string $baseUrl)
    {
        $this->client = new Client([
            'base_uri' => $baseUrl,
            'timeout' => 60,
            'headers' => [
                'Content-Type' => 'application/json',
                'Accept' => 'application/json',
            ]
        ]);
    }

    public function emitir(array $config, array $payload, array $tributacao = []): array
    {
        $response = $this->client->post('/nfe/emitir', [
            'json' => [
                'config' => $config,
                'payload' => $payload,
                'tributacao' => $tributacao,
                'sincrono' => true,
            ]
        ]);

        $body = json_decode($response->getBody(), true);

        if (!$body['success']) {
            throw new Exception($body['error']['message']);
        }

        return $body['data'];
    }

    public function cancelar(array $config, string $chave, string $protocolo, string $justificativa): array
    {
        $response = $this->client->post('/nfe/cancelar', [
            'json' => [
                'config' => $config,
                'chave' => $chave,
                'protocolo' => $protocolo,
                'justificativa' => $justificativa,
            ]
        ]);

        return json_decode($response->getBody(), true)['data'];
    }
}

// Uso
$client = new NfeApiClient('http://localhost:8080');

$result = $client->emitir(
    config: [
        'certificado' => base64_encode(file_get_contents('cert.pfx')),
        'senha' => 'senha',
        'cnpj' => '99999999000191',
        'ambiente' => 2,
        'uf' => 'SP',
    ],
    payload: $nfeData,
    tributacao: $taxDefaults
);

echo "NF-e autorizada: " . $result['chave'];
```

**JavaScript/Node.js - Axios**

```javascript
const axios = require('axios');
const fs = require('fs');

class NfeApiClient {
  constructor(baseUrl) {
    this.client = axios.create({
      baseURL: baseUrl,
      timeout: 60000,
      headers: {
        'Content-Type': 'application/json'
      }
    });
  }

  async emitir(config, payload, tributacao = {}) {
    const response = await this.client.post('/nfe/emitir', {
      config,
      payload,
      tributacao,
      sincrono: true
    });

    if (!response.data.success) {
      throw new Error(response.data.error.message);
    }

    return response.data.data;
  }

  async cancelar(config, chave, protocolo, justificativa) {
    const response = await this.client.post('/nfe/cancelar', {
      config,
      chave,
      protocolo,
      justificativa
    });

    return response.data.data;
  }

  async gerarDanfe(xml, ambiente = 2, stream = false) {
    const response = await this.client.post('/nfe/danfe', {
      xml,
      ambiente,
      stream
    }, {
      responseType: stream ? 'arraybuffer' : 'json'
    });

    if (stream) {
      return response.data; // PDF binário
    }

    return Buffer.from(response.data.data.danfe, 'base64');
  }
}

// Uso
const client = new NfeApiClient('http://localhost:8080');

const certificado = fs.readFileSync('certificado.pfx').toString('base64');

const result = await client.emitir(
  {
    certificado,
    senha: 'senha123',
    cnpj: '99999999000191',
    ambiente: 2,
    uf: 'SP'
  },
  nfePayload,
  tributacaoDefaults
);

console.log('Chave:', result.chave);
console.log('Protocolo:', result.protocolo);
```

**Python - Requests**

```python
import requests
import base64

class NfeApiClient:
    def __init__(self, base_url):
        self.base_url = base_url
        self.session = requests.Session()
        self.session.headers.update({
            'Content-Type': 'application/json'
        })

    def emitir(self, config, payload, tributacao=None):
        response = self.session.post(
            f'{self.base_url}/nfe/emitir',
            json={
                'config': config,
                'payload': payload,
                'tributacao': tributacao or {},
                'sincrono': True
            },
            timeout=60
        )
        
        data = response.json()
        
        if not data['success']:
            raise Exception(data['error']['message'])
        
        return data['data']

    def cancelar(self, config, chave, protocolo, justificativa):
        response = self.session.post(
            f'{self.base_url}/nfe/cancelar',
            json={
                'config': config,
                'chave': chave,
                'protocolo': protocolo,
                'justificativa': justificativa
            }
        )
        
        return response.json()['data']

# Uso
client = NfeApiClient('http://localhost:8080')

with open('certificado.pfx', 'rb') as f:
    certificado = base64.b64encode(f.read()).decode()

result = client.emitir(
    config={
        'certificado': certificado,
        'senha': 'senha123',
        'cnpj': '99999999000191',
        'ambiente': 2,
        'uf': 'SP'
    },
    payload=nfe_data,
    tributacao=tax_defaults
)

print(f"Chave: {result['chave']}")
print(f"Protocolo: {result['protocolo']}")
```

---

## Padrões e Boas Práticas

### 1. Separação de Responsabilidades

```
Controller  → Orquestração HTTP (extrai dados, chama service, retorna response)
Service     → Lógica de negócio (valida, processa, comunica com SEFAZ)
Parser      → Transformação de dados (JSON → XML)
Support     → Utilitários (factory, comunicação, rendering)
```

### 2. Error Handling

```php
// ✅ BOM: Lançar exceção específica
if ($cStat !== '100') {
    throw new SefazRejectionException(
        'NF-e rejeitada',
        $cStat,
        $xMotivo,
        ['chave' => $chave]
    );
}

// ❌ RUIM: Retornar array com erro
if ($cStat !== '100') {
    return ['error' => true, 'message' => 'Rejeitada'];
}
```

### 3. Imutabilidade

```php
// ✅ BOM: Readonly properties
final class EmissaoService
{
    public function __construct(
        private readonly NfeParser $parser,
        private readonly ToolsFactory $toolsFactory
    ) {}
}

// ❌ RUIM: Properties mutáveis
class EmissaoService
{
    private $parser;
    
    public function setParser($parser) {
        $this->parser = $parser;
    }
}
```

### 4. Type Safety

```php
// ✅ BOM: Type hints estritos
public function handle(array $payload, array $tributacao, CertificateConfig $config): array

// ❌ RUIM: Sem tipos
public function handle($payload, $tributacao, $config)
```

### 5. Stateless

```php
// ✅ BOM: Tudo vem do request
$config = new CertificateConfig(...$request->input('config'));
$tools = $this->toolsFactory->make($config);

// ❌ RUIM: Estado global ou sessão
$config = $_SESSION['nfe_config'];
$tools = $GLOBALS['nfe_tools'];
```

### 6. Testabilidade

```php
// ✅ BOM: Dependências injetadas
public function __construct(
    private readonly NfeParser $parser,
    private readonly ToolsFactory $toolsFactory
) {}

// ❌ RUIM: Dependências hard-coded
public function handle() {
    $parser = new NfeParser();
    $tools = new Tools();
}
```

---

## Troubleshooting

### Problema 1: Erro de Certificado

**Sintoma**: `Falha ao assinar o XML da NF-e`

**Causas**:
- Certificado inválido ou expirado
- Senha incorreta
- Certificado não é A1 (.pfx)
- Base64 malformado

**Solução**:
```bash
# Verificar certificado
openssl pkcs12 -info -in certificado.pfx -nodes

# Converter corretamente para Base64
base64 -w 0 certificado.pfx > certificado.txt

# Testar em PHP
$cert = base64_encode(file_get_contents('certificado.pfx'));
```

---

### Problema 2: Timeout SEFAZ

**Sintoma**: `SefazUnavailableException` ou timeout

**Causas**:
- SEFAZ fora do ar
- Firewall bloqueando
- Timeout muito curto

**Solução**:
```php
// Aumentar timeout em SefazComm.php
private const MAX_RETRIES = 3;
private const RETRY_DELAY_MS = 2000;

// Verificar conectividade
curl -v https://nfe.fazenda.sp.gov.br/ws/nfeautorizacao4.asmx
```

---

### Problema 3: Rejeição 539 (Duplicidade)

**Sintoma**: `cStat: 539 - Duplicidade de NF-e`

**Causas**:
- Mesmo número de NF-e já autorizado
- Série/número não incrementados

**Solução**:
```php
// Sempre incrementar nNF
$ultimaNota = $this->getUltimaNota();
$payload['ide']['nNF'] = $ultimaNota + 1;

// Ou usar timestamp para evitar duplicidade em testes
$payload['ide']['nNF'] = (int) date('His');
```

---

### Problema 4: Erro de Schema

**Sintoma**: `O XML montado nao passou na validacao de schema`

**Causas**:
- Campos obrigatórios faltando
- Formato de data incorreto
- Valores fora do range permitido

**Solução**:
```php
// Validar payload antes de enviar
$required = ['ide', 'emit', 'enderEmit', 'det', 'total'];
foreach ($required as $field) {
    if (!isset($payload[$field])) {
        throw new ValidationException("Campo $field obrigatório");
    }
}

// Formatar datas corretamente
$payload['ide']['dhEmi'] = date('Y-m-d\TH:i:sP');

// Validar CNPJ
$cnpj = preg_replace('/\D/', '', $payload['emit']['CNPJ']);
if (strlen($cnpj) !== 14) {
    throw new ValidationException('CNPJ inválido');
}
```

---

### Problema 5: Memória Insuficiente

**Sintoma**: `Allowed memory size exhausted`

**Causas**:
- XML muito grande
- Muitos itens na NF-e
- Limite de memória PHP baixo

**Solução**:
```ini
; php.ini
memory_limit = 512M

; ou via código
ini_set('memory_limit', '512M');
```

---

## Checklist de Implementação

### Setup Inicial
- [ ] PHP 8.2+ instalado
- [ ] Extensões necessárias habilitadas
- [ ] Composer instalado
- [ ] Dependências instaladas (`composer install`)
- [ ] Servidor web configurado

### Configuração
- [ ] Certificado A1 obtido
- [ ] Certificado convertido para Base64
- [ ] Credenciais SEFAZ configuradas
- [ ] Ambiente (homologação/produção) definido

### Testes
- [ ] Health check funcionando (`GET /health`)
- [ ] Pré-visualização gerando DANFE
- [ ] Emissão em homologação bem-sucedida
- [ ] Cancelamento testado
- [ ] CC-e testada
- [ ] Tratamento de erros validado

### Produção
- [ ] Certificado de produção configurado
- [ ] Ambiente alterado para produção (`ambiente: 1`)
- [ ] Logs configurados
- [ ] Monitoramento ativo
- [ ] Backup de XMLs implementado

---

## Recursos Adicionais

### Documentação Oficial
- [Manual de Integração NF-e](http://www.nfe.fazenda.gov.br/portal/principal.aspx)
- [NFePHP Documentation](https://github.com/nfephp-org/sped-nfe)
- [Layout NF-e 4.0](http://www.nfe.fazenda.gov.br/portal/listaConteudo.aspx?tipoConteudo=BMPFMBoln3w=)

### Ferramentas
- [Validador XML SEFAZ](https://www.nfe.fazenda.gov.br/portal/principal.aspx)
- [Consulta Cadastro](https://www.sefaz.rs.gov.br/NFE/NFE-CCC.aspx)
- [Postman Collection](https://www.postman.com/)

### Comunidade
- [NFePHP no GitHub](https://github.com/nfephp-org)
- [Fórum NFePHP](https://github.com/nfephp-org/sped-nfe/discussions)

---

## Conclusão

Esta arquitetura foi projetada para ser:
- **Simples**: Sem frameworks pesados, dependências mínimas
- **Testável**: Injeção de dependências, separação de camadas
- **Extensível**: Fácil adicionar novos endpoints ou impostos
- **Robusta**: Tratamento centralizado de erros, retry automático
- **Stateless**: Escalável horizontalmente, sem estado compartilhado

Adapte conforme necessário para seu caso de uso específico!
