# Technical Context

Como a construção está descrita no material já existente. Fontes: documentação de arquitetura de 06/10/2026 (versão 1.0, branch `qas`), `specs/data-model.md`, `specs/api.yaml` e `specs/traceability.md` (os três gerados em 2026-09-29T20:10:00.000Z). Identificadores no formato RF-001 são os do `epic/spec.md`; o código entre parênteses é o do catálogo.

Não há, neste repositório de metadados, o código do produto. O desenho abaixo é o que esses documentos registram.

## Arquitetura

Fonte: `relatorios-produtos-3-4/anexos/GEF - Documentação de arquitetura.md`. O documento vale para os Produtos 3 e 4 e descreve o estado da branch `qas` em 06/10/2026. Nessa data, o ambiente de testes publica a consulta pública; a Área do Gestor está desenhada e ainda em revisão.

A plataforma publica e consulta o Valor de Conservação. O índice é produzido pelo IIS em parceria com a SBio/MMA. Nenhum componente recalcula o valor. Quem consulta o mapa não faz login.

A aplicação roda em contêineres, com um único ponto de entrada. A mesma imagem vai do ambiente de testes à produção; o que muda é variável de ambiente. Leitura pública e escrita administrativa ficam separadas por papel de banco e por sessão. Só a última etapa da carga muda o que o público vê, e de uma vez.

| Camada | O que o documento registra |
|---|---|
| Apresentação | Portal em React, com o visualizador de mapa |
| Serviços | API, worker de carga e servidor de mapas |
| Dados | PostgreSQL com PostGIS e armazenamento de objetos |

| Componente | Papel registrado |
|---|---|
| nginx de borda | Única porta publicada. Encaminha `/` ao portal, `/api` à API e `/geoserver` ao servidor de mapas |
| Portal | Mapa, busca, filtros, ficha, indicadores e exportação |
| API | Consulta pública e, quando publicada, a Área do Gestor. Um único processo |
| Worker | Recebe o arquivo do IIS, valida, integra ao CAR e publica. Processo separado da API. Comando em uso: `gef-worker carregar` |
| Servidor de mapas | Entrega os tiles. O cache evita redesenhar a mesma região |
| Banco | Referência, imóveis, valor, publicação, administração e auditoria |
| Armazenamento de objetos | Fora da produção, Silo (API S3). Em produção, o S3 que a infraestrutura do Ministério disponibilizar. Três buckets privados: arquivo como chegou, raster convertido e exportações. Nenhum é público |

O navegador pede Ruas (OpenStreetMap) e Satélite (Esri) direto ao provedor. Se o provedor não responde, as camadas do observatório continuam.

Enquanto nenhum raster for entregue, o Valor de Conservação é desenhado pelo tile vetorial dos imóveis, em todos os níveis de zoom, colorido pela faixa que o tile traz. A superfície raster entra quando o arquivo correspondente for carregado.

### Fluxo de carga

O arquivo de entrada registrado é o shapefile do IIS: um polígono por imóvel, com o recibo do CAR e o valor. O conjunto precisa de `.shp`, `.shx` e `.dbf`. As seis etapas param na primeira que falha. Arquivo que não pode ser publicado gera o relatório de inconsistências e deixa a versão anterior no ar.

| Etapa | O que faz |
|---|---|
| Recebimento | Copia o conjunto, como foi entregue, para o armazenamento de staging. Se o armazenamento não aceitar, nada é gravado no banco da carga |
| Validação | Confere campos, recibo, geometria, faixa do valor (0 a 1) e ausência de coluna de dado pessoal. Cada inconsistência vira uma linha: arquivo, linha, recibo, campo e motivo |
| Preparação | Deixa o polígono em SIRGAS 2000, como MultiPolygon válido. Correção que tem conserto entra no relatório. A conversão de raster para COG está reservada nesta etapa e ainda não está implementada |
| Carga | Grava a versão nova. A consulta pública continua na anterior |
| Integração | Liga o valor ao imóvel pelo recibo, sem recalcular, e grava o agregado do recorte (bioma, UF, município e faixa) na mesma operação |
| Publicação | Troca a versão publicada de uma vez e pede a limpeza do cache de tiles dos imóveis. Falha nessa limpeza não desfaz a publicação |

As malhas do IBGE (biomas, unidades da federação e municípios) não passam por essa fila. Entram antes e servem para localizar o imóvel. Nessa documentação, a cobertura marcada é Mata Atlântica e Cerrado.

[NEEDS CLARIFICATION: esse recorte de dois biomas contradiz RN-003 e RF-004 em `discovery/index.json` (2026-11-03), que falam em cinco biomas. Ver `epic/spec.md`.]

Depois da publicação, a consulta lê essa versão: o mapa pelos tiles, e a lista, a ficha e os indicadores pela API. Filtro só de bioma, UF, município e faixa soma o agregado gravado na carga. Filtro de valor, busca ou recibo agrupa na hora sobre os imóveis publicados. Os dois caminhos devolvem a mesma forma de número.

### Decisões registradas

| Decisão | O que ficou valendo |
|---|---|
| API em um processo só | Nove módulos: referência, imóvel, indicador, camada, carga, conteúdo, acesso, auditoria e notificação, com fronteira verificada no build. A carga pesada fica no worker |
| Autenticação na própria API | O portal público não tem login. A Área do Gestor entra por sessão no banco, senha só como hash. Login gov.br ficou fora deste contrato |
| Banco | PostgreSQL 16 com PostGIS. Seis schemas. Três papéis: quem cria estrutura, quem grava linhas, e quem só lê o que o mapa publica. O servidor de mapas não alcança administração nem auditoria. Geometria em SIRGAS 2000 |
| Mapa num servidor, consulta na API | Tiles e cache no servidor de mapas. Busca, lista, ficha e indicadores saem da API. Um único cache de tiles atende as combinações de filtro, porque o filtro de bioma, UF, município e faixa acontece no navegador, sobre o tile |
| Cache da carga | O worker, ao publicar, limpa o cache da camada de imóveis. Se a limpeza falha, a versão nova já vale e o relatório registra o cache em atraso |
| Worker | Python com GDAL. Fila no próprio banco |
| Indicadores | A carga grava um agregado por versão. A tela soma esse agregado quando o filtro cabe nele. Não há média de valor por município nem por estado |
| Exportação | Excel, PDF e CSV nascem na API a cada pedido, em memória, com os mesmos números do card. O arquivo não é guardado |
| Textos de ajuda | Ficam numa tabela e a API os serve em rota pública. A edição espera a Área do Gestor |
| Identidade visual | Design system próprio. O padrão visual do gov.br foi a primeira base e foi substituído, combinado com o cliente |

O que a arquitetura ainda descreve e o ambiente de testes, em 06/10/2026, ainda não executa:

- conversão de raster para COG e a superfície do Valor de Conservação por WMS/WMTS;
- publicação das sete variáveis temáticas, cada uma quando o arquivo chegar;
- Área do Gestor no ar (login, cargos, confirmação e histórico).

[NEEDS CLARIFICATION: os nomes dos seis schemas, os nomes dos três papéis de banco, o desenho das tabelas relacionais e as rotas HTTP desses nove módulos não estão nesse documento.]

[NEEDS CLARIFICATION: a leitura por território (RF-015), o registro de uso (RF-016) e a recuperação de senha (RF-017) não aparecem nessa arquitetura de 06/10/2026. RF-016 e RF-017 entram no discovery em 04/10 e 05/10 de 2026; a arquitetura não os descreve.]

## Modelo de dados

Fonte: `specs/data-model.md`. O próprio arquivo diz que entidades e operações foram levantadas das interfaces `repo.js` e dos registros `store` de cada slice do MVP, e que estrutura não declarada no código não é inventada.

Isto não é o modelo PostgreSQL da arquitetura. Não há chave, tipo, cardinalidade nem relação entre slices.

| Slice | Intenção registrada | Coleções | Operações de repositório |
|---|---|---|---|
| `administracao` | Área do gestor com login interno, painel, usuários, cargos, camadas, conteúdos, confirmação e histórico | `administracao`, `usuarios`, `cargos`, `camadas`, `conteudos`, `historico` | `apagarRascunhoTooltip`, `carregarPainel`, `gravarAtualizacaoPublica`, `gravarTooltipsPublicos`, `guardarRascunhoTooltip`, `guardarRegistro`, `guardarSessao`, `lerAtualizacaoPublica`, `lerRascunhoTooltip`, `lerSessao`, `salvarPainel` |
| `consulta` | Consulta do imóvel | `consulta` | `guardarRegistro`, `listarRegistros` |
| `dados` | Carga e publicação | `dados` | `guardarRegistro`, `listarRegistros` |
| `entrega` | Marcos e artefatos da entrega | `entrega`, `marcos`, `artefatos` | `guardarRegistro`, `listarRegistros` |
| `indicadores` | Números do recorte | `indicadores` | `guardarRegistro`, `listarRegistros` |
| `mapa` | Mapa público, filtros, estatísticas, tooltips e exportação | `mapa`, `comparacao`, `sugestoes`, `sugestoesFiltro`, `tooltips` | `apagarRascunhoTooltip`, `guardarRascunhoTooltip`, `guardarRegistro`, `lerAtualizacaoPublica`, `lerMarcaExportacao`, `lerRascunhoTooltip`, `lerTooltips`, `listarMunicipios`, `listarRegistros` |

Os campos de cada store estão listados em `specs/data-model.md`. São campos de estado de tela e de coleção, sem tipo.

Requisitos do discovery sem slice nesse modelo:

- RF-015 (leitura por território) — [NEEDS CLARIFICATION: não há entidade `prioridade` em `specs/data-model.md`]
- RF-016 (registro de uso) — [NEEDS CLARIFICATION: não há coleção de acessos, tempo de navegação ou período]
- RF-017 (recuperação e troca de senha) — [NEEDS CLARIFICATION: não há campo de link de uso único, segundo e-mail, código de recuperação nem prazo de 24 horas]

A arquitetura nomeia o que o banco guarda (referência, imóveis, valor, publicação, administração e auditoria) e uma tabela de textos de ajuda, sem colunas. A validação da carga cita faixa de 0 a 1, recibo, geometria MultiPolygon em SIRGAS 2000 e agregado por bioma, UF, município e faixa.

[NEEDS CLARIFICATION: não há correspondência escrita entre os slices do MVP e os seis schemas do PostgreSQL.]

## Contratos

Há dois contratos no material, e eles não são o mesmo.

### Contrato levantado do MVP

Fonte: `specs/api.yaml` (OpenAPI 3.0.3, título «Observatório GEF — API levantada do MVP», versão v1, `x-generated-at` 2026-09-29T20:10:00.000Z). Cada rota deriva de um `@action`. O corpo é um objeto sem propriedades declaradas. A resposta de sucesso registrada é `201`. Rotas marcadas `x-simulado: true` aparentam uma garantia que `specs/honesty.md` trata como simulada.

| Rota | Operação | Requisitos no contrato | Simulado |
|---|---|---|---|
| `POST /administracao/administrarPublicacao` | `administrarPublicacao` | RF06 | sim |
| `POST /administracao/atualizarCamada` | `atualizarCamada` | RF06, RN04 | |
| `POST /administracao/atualizarConteudo` | `atualizarConteudo` | RF06, RF13, RN04 | |
| `POST /administracao/cancelarMudanca` | `cancelarMudanca` | RN04 | |
| `POST /administracao/confirmarMudanca` | `confirmarMudanca` | RN04, RF12 | |
| `POST /administracao/criarCargo` | `criarCargo` | RF11, RN04 | |
| `POST /administracao/descartarRascunho` | `descartarRascunho` | RF13 | |
| `POST /administracao/entrarNaArea` | `entrarNaArea` | RF10, RF06 | |
| `POST /administracao/excluirConteudo` | `excluirConteudo` | RF13, RN04 | |
| `POST /administracao/incluirConteudo` | `incluirConteudo` | RF13, RN04 | |
| `POST /administracao/prepararPosicionamento` | `prepararPosicionamento` | RF13 | |
| `POST /administracao/registrarUsuario` | `registrarUsuario` | RF11, RN04 | sim |
| `POST /administracao/retomarSessao` | `retomarSessao` | RF10 | |
| `POST /administracao/sairDaArea` | `sairDaArea` | RF10 | |
| `POST /consulta/consultarImovel` | `consultarImovel` | RF03 | |
| `POST /consulta/filtrarImoveis` | `filtrarImoveis` | RF04, RN02, RN03 | |
| `POST /dados/publicarDados` | `publicarDados` | RF07, RN01 | |
| `POST /entrega/consultarMarcos` | `consultarMarcos` | RF09 | |
| `POST /entrega/registrarEntrega` | `registrarEntrega` | RF08 | sim |
| `POST /indicadores/atualizarIndicadores` | `atualizarIndicadores` | RF05, RN02 | |
| `POST /mapa/abrirPosicionamento` | `abrirPosicionamento` | RF13 | |
| `POST /mapa/ajustarEstatisticas` | `ajustarEstatisticas` | RF05, RN02 | |
| `POST /mapa/buscarNaBarra` | `buscarNaBarra` | RF04, RN02, RN03, CA11, CA28, CA29, CA30, CA31, CA32 | |
| `POST /mapa/cancelarPosicionamento` | `cancelarPosicionamento` | RF13 | |
| `POST /mapa/compararImoveis` | `compararImoveis` | RF03, RN02 | |
| `POST /mapa/concluirPosicionamento` | `concluirPosicionamento` | RF13 | |
| `POST /mapa/exibirCamadas` | `exibirCamadas` | RF02, RN01, RN03 | |
| `POST /mapa/exportarEstatisticas` | `exportarEstatisticas` | RF14, RF05, RN02 | |
| `POST /mapa/fecharAviso` | `fecharAviso` | RF04 | |
| `POST /mapa/filtrarImoveisMapa` | `filtrarImoveisMapa` | RF04, RN02, RN03 | |
| `POST /mapa/mostrarTooltips` | `mostrarTooltips` | RF12, RF13 | |
| `POST /mapa/mostrarUltimaAtualizacao` | `mostrarUltimaAtualizacao` | RF12 | |
| `POST /mapa/moverTooltip` | `moverTooltip` | RF13 | |
| `POST /mapa/navegarMapa` | `navegarMapa` | RF01 | sim |
| `POST /mapa/sugerirBusca` | `sugerirBusca` | CA27 | |
| `POST /mapa/sugerirFiltro` | `sugerirFiltro` | RF04, RN03 | |

`filtrarImoveis`, `filtrarImoveisMapa`, `sugerirFiltro` e `exibirCamadas` descrevem o recorte Mata Atlântica e Cerrado. [NEEDS CLARIFICATION: esse texto do contrato não foi atualizado para os cinco biomas de RN-003 e RF-004.]

`exibirCamadas` diz que variável ausente usa número simulado marcado na ficha. [NEEDS CLARIFICATION: CA-006 diz que a plataforma não inventa esse dado.]

`compararImoveis` limita a comparação a três imóveis. [NEEDS CLARIFICATION: RF-003 não declara esse limite.]

Requisitos posteriores a 29/09/2026 sem rota neste arquivo: RF-015, RF-016, RF-017, e os CA-055 a CA-073. `specs/traceability.md` cita `administracao/actions.js#mostrarUso` para RF16, e essa operação não está em `paths`.

### Contrato da consulta pública na branch qas

Fonte: `relatorios-produtos-3-4/anexos/openapi-qas.yaml`. O cabeçalho do arquivo diz que é a leitura editável dos caminhos e dos dados da branch `qas` em 06/10/2026, e que não é a cópia byte a byte do arquivo do repositório do produto. OpenAPI 3.1.0. Servidor: `/api`. A descrição cobre a consulta pública do Valor de Conservação na Mata Atlântica e no Cerrado, e operações da Área do Gestor.

[NEEDS CLARIFICATION: os paths deste arquivo são só GET da consulta pública. Não há path de login, usuário, cargo, camada administrativa, confirmação, histórico, uso nem senha, apesar da descrição citar a Área do Gestor.]

[NEEDS CLARIFICATION: a descrição de `/v1/camadas` fala em doze camadas na ordem do painel. A lista desses doze códigos não está no arquivo.]

| Método e caminho | Operação | O que o arquivo registra |
|---|---|---|
| `GET /v1/biomas` | `biomas` | Lista biomas e marca os cobertos nesta versão. Schema `Bioma`: `codigo`, `nome`, `coberto` |
| `GET /v1/ufs` | `ufs` | Lista as unidades da federação. Com `coberto=true`, só as que têm município com parte num bioma coberto |
| `GET /v1/municipios` | `municipios` | Sugere municípios no formato município-UF. Parâmetros: `texto`, `uf`, `codigo` (7 dígitos), `coberto` (padrão false), `limite` de 1 a 40 (padrão 10). Schema `MunicipioSugerido`: `codigo`, `nome`, `uf`, `rotulo`, `coberto` |
| `GET /v1/municipios/{codigo}` | `municipio` | Ficha para enquadrar o mapa. Caixa oeste, sul, leste, norte da parte do município dentro dos biomas cobertos. Schema `MunicipioFicha` |
| `GET /v1/camadas` | `catalogo` | Catálogo. Variável não entregue consta como `entregue: false`. Schema `ItemDto`: `codigo`, `nome`, `grupo`, `entregue`, `ordem`, `camadaServidor`, `atributo`, `faixas`, `subcamadas` |
| `GET /v1/imoveis` | `listar` | Lista paginada. Filtros: `bioma`, `uf`, `municipio`, `faixa`, `vcMin`, `vcMax`, `busca`, `recibo`, `pagina` (padrão 1), `tamanho` (padrão 20). Schema `PaginaDaLista` |
| `GET /v1/imoveis/{recibo}` | `ficha` | Ficha pelo recibo. 400 se o recibo está fora do formato. 404 se não está publicado. Schema `FichaDoImovel` |
| `GET /v1/recibos/{recibo}` | `situacao` | Situação: `publicado`, `fora_da_versao` ou `nao_encontrado` |
| `GET /v1/indicadores` | `indicadores` | Mesmos filtros da lista. Não há média por município nem por estado. Schema `IndicadoresDoRecorte` |
| `GET /v1/indicadores/exportacao` | `exportar` | Anexo `estatisticas-deste-conjunto` em `xlsx`, `pdf` ou `csv`. Também `variavel` e `medida` (`imoveis` ou `area`). 400 se formato, medida, variável ou filtro está fora dos aceitos |
| `GET /v1/atualizacao` | `atualizacao` | Instante em que a versão de carga publicada passou a valer. Sem carga publicada, `ultimaAtualizacao` vem nulo |
| `GET /v1/tooltips` | `tooltips` | Textos de ajuda. Schema `TooltipDto`: `local`, `texto` |

`FichaDoImovel` registra `recibo`, `municipio`, `uf`, `bioma`, `areaHa`, `modulosFiscais`, `situacaoCar`, `valorConservacao`, `faixa`, `variaveis` (`codigo`, `nome`, `valor`), `contorno` (GeoJSON MultiPolygon em SIRGAS 2000), `bbox` e `pontoInterno`.

`IndicadoresDoRecorte` registra `imoveis`, `areaHa`, `municipios`, `faixas` (`imoveis` e `areaHa` por faixa), `biomas` (`imoveis` e `areaHa` por bioma), `ufs` (`imoveis` e `areaHa` por UF) e `foraDaVersao`.

`Faixa` registra `codigo`, `nome`, `limiteInferior` e `limiteSuperior`. Os valores desses limites não estão no arquivo.

[NEEDS CLARIFICATION: este contrato não liga cada path a um RF. A ligação abaixo é só o assunto coincidente com o catálogo, não uma rastreabilidade declarada no yaml: biomas/ufs/municípios e lista com RF-004; ficha com RF-003; camadas com RF-002; indicadores com RF-005; exportação com RF-014; atualização com RF-012; tooltips de leitura com RF-013. Não há path para RF-001 (navegação e mapa-base, que a arquitetura tira do servidor de mapas e dos provedores), RF-006 a RF-011, RF-015 a RF-017, RN-004 nem RNF-001 a RNF-003.]

Tiles continuam fora deste yaml. A arquitetura os entrega em `/geoserver`. A fila do worker fica no banco e também não está neste contrato.
