76 lines
7.8 KiB
Markdown
76 lines
7.8 KiB
Markdown
# SuiteCrmClient — contrato implementado
|
||
|
||
Estado: cliente Laravel implementado e testado com HTTP simulado. Não há SuiteCRM instalado, credenciais criadas, tráfego real ou integração com as manifestações. Não activar apenas por estes testes passarem.
|
||
|
||
## Ficheiros desta entrega
|
||
|
||
| Ficheiro | Finalidade |
|
||
| ------------------------------------------------- | ------------------------------------------------- |
|
||
| `app/Integrations/SuiteCrm/SuiteCrmClient.php` | Cliente OAuth2/JSON:API |
|
||
| `app/Integrations/SuiteCrm/SuiteCrmException.php` | Erro sanitizado e metadados de recuperação |
|
||
| `config/suitecrm.php` | Desactivação por defeito, URLs, módulos e limites |
|
||
| `.env.example` | Variáveis backend sem credenciais reais |
|
||
| `tests/Feature/SuiteCrm/SuiteCrmClientTest.php` | Testes de contrato local, recuperação e segurança |
|
||
|
||
Sem novas dependências Composer, rotas, migrations ou chamadas desde o frontend. A configuração usa o cache database existente; os testes usam array e não precisam de uma base de dados. Em implantação com vários workers, todos devem partilhar o cache e os locks.
|
||
|
||
## Contrato HTTP
|
||
|
||
A base configurada é a URL HTTPS da aplicação legacy que contém `Api`; o prefixo real será confirmado na instalação. Todos os caminhos abaixo são relativos a essa base.
|
||
|
||
| Método Laravel | HTTP | Caminho | Contrato |
|
||
| -------------------- | ----- | -------------------------------------------------------- | ------------------------------------------------------------------------------- |
|
||
| Autenticação interna | POST | `/Api/access_token` | `grant_type=client_credentials`, client ID/secret; resposta Bearer com validade |
|
||
| `find` | GET | `/Api/V8/module/{module}/{id}` | Registo autorizado |
|
||
| `search` | GET | `/Api/V8/module/{module}` | Filtros exactos combinados por AND; página >=1; tamanho 1–100 |
|
||
| `create` | POST | `/Api/V8/module` | Envelope `data.type` e `data.attributes` |
|
||
| `update` | PATCH | `/Api/V8/module` | Envelope com tipo, ID e atributos |
|
||
| `relate` | POST | `/Api/V8/module/{module}/{id}/relationships/{linkField}` | Tipo e ID do registo relacionado |
|
||
| `fields` | GET | `/Api/V8/meta/fields/{module}` | Metadados para validar o mapeamento |
|
||
|
||
O cliente devolve o documento JSON, preservando paginação. Não segue links de paginação devolvidos pelo servidor; o consumidor pede explicitamente a página seguinte. Módulos são limitados à allowlist de configuração; nomes e IDs não aceitam separadores de caminho. Métodos não são endpoints públicos e não substituem autorização de negócio, validação dos atributos ou permissões da conta técnica.
|
||
|
||
Os formatos foram confrontados com `public/legacy/Api/V8/Config/routes.php` no pacote oficial SuiteCRM 8.10.2 de SHA-256 `ac4693d10ea2d6cd20b3256098781d134599d88878fb24e8dc127038d624f5a8`. Os testes são contratos do consumidor com respostas simuladas; ainda falta provar compatibilidade contra o servidor.
|
||
|
||
## Tokens e segredos
|
||
|
||
HTTPS e validação do certificado são obrigatórios; redirects são recusados. A URL não pode conter credenciais, query ou fragmento. Tokens são cifrados com a chave Laravel antes de entrar no cache e expiram antecipadamente. Obtenção e invalidação usam locks. Se outra chamada já renovou o token, um 401 atrasado não deve apagar o token novo.
|
||
|
||
Client credentials obtém novo token na expiração; não presume refresh token. Um 401 da API permite uma renovação e repetição. O segundo 401 termina a operação. Alterar o segredo muda o namespace do cache; reiniciar workers/reconstruir o cache de configuração durante rotação. Revogar o cliente antigo no CRM; a mudança local não o revoga remotamente.
|
||
|
||
O segredo deve ser injectado no ambiente do backend por mecanismo privado. Não usar variáveis `VITE_`. O `.env` actual não foi alterado. Não imprimir configuração, payloads ou respostas de autenticação no diagnóstico.
|
||
|
||
## Retries, circuit breaker e ambiguidade
|
||
|
||
- Consultas: até duas repetições para falhas de rede, 429 e 5xx, com backoff exponencial e jitter.
|
||
- Retry-After numérico/data é respeitado. Atrasos superiores a cinco segundos são devolvidos ao futuro job, sem bloquear o processo; valor limitado a um dia.
|
||
- Criação, actualização e relação: não repetir automaticamente após timeout ou 5xx. `outcomeUnknown=true` exige consultar a identidade externa/reconciliar antes de reenviar.
|
||
- 403, 404, 409 e 422 são erros permanentes neste nível; a lógica de negócio decide a recuperação.
|
||
- Cinco operações com falha transitória abrem o circuito durante 60 segundos. O contador usa lock. Após o intervalo, operações voltam a ser permitidas; ainda não há controlo de uma única sonda half-open.
|
||
- Sucesso com JSON inválido é rejeitado; numa escrita, é considerado ambíguo.
|
||
|
||
`retryable` indica natureza transitória, não autorização para repetir uma escrita. O futuro processador da outbox deve respeitar também `outcomeUnknown` e `retryAfter`. O cliente isolado não implementa idempotência distribuída nem fusão de contactos.
|
||
|
||
## Observabilidade
|
||
|
||
Cada tentativa produz `suitecrm.http` com operação, código HTTP e duração em milissegundos. Não inclui URL, IDs, corpos, atributos ou cabeçalhos. Excepções usam razões enumeradas e não encadeiam a excepção HTTP original. Há atributos SensitiveParameter nos argumentos com dados pessoais/segredos.
|
||
|
||
Esses eventos permitem agregar taxa de falhas/latência; ainda não há exporter, dashboard ou alertas instalados. Instrumentação externa que capture HTTP (debuggers/APM) deve ser configurada para excluir tokens e payloads antes de activar a integração.
|
||
|
||
## Verificação e limites
|
||
|
||
15 testes, 62 asserções, sem rede real: desactivação, HTTPS, tokens cifrados, reutilização, expiração, rotação, 401 limitado, formato JSON:API, retry de leitura, escrita ambígua, Retry-After, circuito, módulos/IDs/paginação, sanitização e resposta inválida. PHPStan passou sem erros.
|
||
|
||
A suite completa também passou: 85 testes e 612 asserções. Pint, formatação e lint passaram. Não foi necessário alterar ou testar o frontend visual, pois esta entrega não o modifica.
|
||
|
||
Ainda faltam: testes reais e concorrência entre processos; configuração OAuth; RBAC no CRM; documentos binários; outbox/inbox e jobs; reconciliação; métricas/alertas; relação com consentimento e domínios do portal. Metadados de Documents podem ser enviados por `create` após validação do esquema; não existe upload binário genérico implementado.
|
||
|
||
## Rollback
|
||
|
||
Manter `SUITECRM_ENABLED=false`. Como nenhum fluxo do portal chama o cliente, esta entrega não altera dados comerciais. Ao remover os ficheiros, retirar também a configuração e variáveis de exemplo. Se o cliente tiver sido activado numa instalação futura, desactivar envios e revogar o OAuth; não considerar isso reversão de registos já escritos no CRM.
|
||
|
||
## Referências
|
||
|
||
- [Endpoints oficiais](https://docs.suitecrm.com/developer/integration-api/v8/endpoints/)
|
||
- [Autenticação oficial](https://docs.suitecrm.com/developer/integration-api/v8/authentication/)
|