# ADR-002 — Mínimas dependências, vendorização e licenças permissivas

| Campo | Valor |
|---|---|
| **Status** | Aceito (2026-10-16) |
| **Data** | 2026-10-14 |
| **Plano de origem** | `wiki/plan/03-esqueleto-ddd-lite.md` |
| **Relacionadas** | ADR-001, ADR-009, ADR-010, ADR-020, ADR-019 |

## Contexto

O projeto prioriza **simplicidade** e **nativo primeiro** (ADR-001). Dependências externas trazem
risco (CVEs), peso, obrigações de licença e quebra de *supply chain*. O legado (`prefeituras_v5`,
`v6-hardening`) sofreu com CDNs de terceiros, múltiplas bibliotecas duplicadas e pacotes sem
justificativa. "Uso do que já está posto" e "poucas dependências" são **fundamentos**, não detalhes.

## Decisão

- **Nativo primeiro:** exaurir Laravel/PHP **antes** de qualquer pacote (ADR-001).
- **Zero CDN, com apenas DUAS exceções nomeadas:** todo asset (JS/CSS/fontes/ícones) é
  **vendorizado/buildado localmente** (Vite 8). As **únicas** requisições externas aceitas pelo
  projeto são:
  1. **VLibras** (`vlibras.gov.br`) — serviço oficial de acessibilidade (gov.br), carregado
     **sob demanda** (só quando o usuário aciona); é requisito de acessibilidade, não conveniência.
  2. **Google Analytics** (`googletagmanager.com`/`google-analytics.com`) — **desligado por padrão**;
     só é emitido quando o **painel de suporte** (ainda a construir) configura o ID. Opt-in
     explícito do cliente; sem ID configurado, **nenhuma** requisição externa acontece.

  O gate `tools/vendor-check` mantém uma **allowlist fechada** com exatamente esses dois domínios:
  qualquer outro recurso externo **falha o build**. A allowlist só muda com **ADR própria**.
- **Licenças permissivas apenas** (MIT/ISC/Apache-2.0/BSD/OFL); `THIRD_PARTY_LICENSES` mantido.
- **Toda dependência é justificada** pelo que resolve que o nativo não resolve; preferir
  extensões PHP/ferramentas já no container a pacotes Composer.
- **Exceções admitidas (justificadas):** `league/flysystem-aws-s3-v3` (disco S3 do Laravel,
  ADR-030) e o backend de object storage **RustFS** (Apache-2.0) — ambos permissivos.
- **Vendorização de binários/ícones/fontes** via build (ex.: Lucide SVG), **nunca** runtime de terceiros.
- **Serviços de terceiros** (WAF/CDN/analytics/tag manager) são **proibidos por padrão**
  (ADR-020/ADR-019), **salvo as duas exceções acima**; qualquer outra exceção exige ADR própria.
- **Analytics por padrão é privacy-first e first-party** (ADR-019/ADR-027): HyperLogLog, sem PII.
  O Google Analytics é a exceção opt-in — quando ativo, é **consent-gated** (LGPD) e o carregamento
  é feito por JS **same-origin** (sem `<script>` inline — ADR-022).

### Emenda (F3/F4, 2026-10-17) — escopo de licença além do `composer.lock`

A verificação de licenças cobria **só** o `composer.lock` (`tools/licenses-check.php`). Auditoria de
F3/F4 revelou três fontes que escapavam e agora têm **gate próprio** (`tools/assets-licenses-check.php`,
parte do `make check`). O relatório é **um único artefato** (`THIRD_PARTY_LICENSES`) com uma seção
por dono — `composer` e `assets` —, cada uma reescrita e verificada pelo seu gerador:

1. **npm** (build/front-end): allowlist permissiva igual à do composer. Exceção **nomeada e estreita**:
   `lightningcss*` em **MPL-2.0** — copyleft fraco, **ferramenta de build** (Tailwind 4), não
   distribuída; nenhuma obrigação alcança o nosso código.
2. **Assets vendorizados**: fontes **OFL-1.1** (com `LICENSE-OFL.txt` ao lado), ícones **Lucide (ISC)**
   com declaração no cabeçalho e **Simple Icons (CC0-1.0)** documentado — tudo verificado pelo gate.
3. **Binários externos invocados em runtime** (não aparecem em lock nenhum):
   - **permitidos**: `vips`/`vipsheader` (**libvips, LGPL-2.1-or-later**) e `qpdf` (**Apache-2.0**).
     A LGPL é aceitável aqui porque o serviço **invoca o binário como processo separado** (sem
     *linking* nem redistribuição modificada do nosso código) — a folha de licença da biblioteca
     acompanha a imagem base.
   - **bloqueados** (o gate falha se aparecerem no código ou na imagem): **Ghostscript (AGPL-3.0)** e
     **poppler/`pdftotext` (GPL-2.0)**. Eles eram usados no pipeline de PDF (PDF/A e extração de texto)
     e foram **removidos**; PDF/A fica pendente de uma decisão própria (encoder permissivo ou serviço
     externo licenciado).

**Consequência:** "licença permissiva" passa a ser verificável **de ponta a ponta** (composer + npm +
assets + binários) e nenhum copyleft forte pode entrar por um `Process::run` esquecido.

## Justificativa (alternativas descartadas)

- **CDN de terceiros (genérico)** — descartada: indisponibilidade, privacidade, zero-CDN
  (ADR-009/ADR-010). Exceções só para **serviços oficiais/opt-in** (VLibras; GA configurado no painel).
- **"Um pacote para cada coisa"** — descartada: peso, licenças e superfície de ataque.
- **Fontes/ícones remotos** — descartada: o projeto serve tudo da própria origem.

## Consequências

**Positivas**
- Menor superfície, menos CVEs, sem lock-in de fornecedor, licenças controladas.
- Builds reprodutíveis e offline.

**Custos / negativas**
- Mais trabalho manual pontual (vendorizar/atualizar binários).
- Atualizações de lib exigem rebump versionado no path.

## Exemplo mínimo (comparativo)

```html
{{-- ❌ CDN externo --}}
<link href="https://cdn.example.com/lib.css" rel="stylesheet">
<script src="https://cdn.example.com/lib.js"></script>

{{-- ✅ vendorizado/buildado (Vite 8 + public/assets/vendor) --}}
<link href="{{ Vite::asset('resources/.../lib.css') }}" rel="stylesheet">
```

## Verificação

- `tools/vendor-check` verde com **allowlist fechada** (`vlibras.gov.br`, `googletagmanager.com`,
  `google-analytics.com`): fixture válida passa, qualquer outro domínio falha.
- Sem `google_analytics_id` configurado, a página **não** emite nenhuma requisição externa
  (teste automatizado).
- Nenhum `<script>`/`<link>` inline apontando para terceiros em runtime (ADR-022).
- `composer audit` / `npm audit` no CI; licenças na allowlist; `THIRD_PARTY_LICENSES` (composer) e
  `THIRD_PARTY_LICENSES_ASSETS` (npm + assets + binários) atualizados.
- `tools/assets-licenses-check.php` reprova fixture com pacote GPL e com `Process::run(['gs', …])`
  (`tools/gates-selftest.sh`) — copyleft forte não entra por dependência nem por binário.

## Referências

- `wiki/plan/05-qualidade-phpstan-max.md` (`tools/vendor-check`); ADR-001, ADR-009, ADR-010.
