Engenharia do
Vetorizador
Uma revista técnica sobre a arquitetura, módulos, contratos e evolução do Vetorizador — software desktop para produção geoespacial e documental com núcleo determinístico Rust/WASM.
Índice dos Capítulos
- 01Visão Geral da Arquitetura
- 02Subsistemas
- 03Pipeline de Seleção
- 04Fronteiras Arquiteturais
- 05Padrões GoF
- 06Módulos Core
- 07Módulos de Suporte
- 08Desktop & APIs
- 09Fluxo de Vetorização
- 10SIGEF & Memorial
- 11Desambiguação Global
- 12Snap & Auto-vertex
- 13CONFIG & Estado de Sessão
- 14Persistência Local
- 15Contrato WASM
- 16Sistema de Diagnóstico
- 17Rastreabilidade RF
- 18Requisitos Não Funcionais
- 19Evolução & Escala
- 20Build & Runbooks
Visão Geral da Arquitetura
O Vetorizador é um sistema desktop composto por renderer local em Electron, serviços locais em Node/Python e um núcleo determinístico de vetorização em Rust/WebAssembly. A arquitetura prioriza entrega operacional local-first.
Fluxo arquitetural principal
UI Leaflet + Controles
Usuário localiza área, desenha ROI e configura preset.
Pré-processamento JS
Realce de contraste, Sobel, Otsu, morfologia e DBSCAN opcional.
vetoriza_imagem (Rust/WASM)
Núcleo determinístico converte imagem em polígonos GeoJSON.
Seleção, revisão e desambiguação
Guardrails por preset, regularização geométrica, modal de desambiguação entre fontes sobrepostas, Shift multi-select cruzado.
Exportação / Persistência local
GeoJSON, Shapefile, memorial DOCX ou relatório PDF. No confronto SIGEF, ZIP com SHP de polígono + pontos de vértice (DE/PARA). Runs e feedback persistidos em IndexedDB.
Subsistemas
O produto é organizado em 6 subsistemas com responsabilidades bem delimitadas.
Shell principal de interface
index.html, style.css, app.js — mapa, navegação entre modos, exibição de resultados e embed do PDFSpliter.
Pipeline de vetorização
app.js, geo-postprocess.js, scene-classifier.js, vetoriza/src/lib.rs — captura ROI → WASM → pós-processamento → exportação.
Persistência e estado
app-boundary-manager.js + trechos de app.js — IndexedDB operacional, localStorage, camada de referência APP local por instalação.
Serviços embarcados e APIs
api/pdf-to-geojson/*, api/shp-to-geojson/* — OCR, PDFtoArcGIS, conversão SHP local.
Confrontação SIGEF & Memorial
sigef-wfs.js, sigef-memorial.js, app.js — consulta WFS, importação SHP SIGEF (polígono ou pontos), seleção/desambiguação de referência, confronto de vértices, geração de DOCX e exportação SHP dupla (polígono + pontos) com cota Z.
Runtime desktop
desktop/main.cjs, desktop/app-server.cjs, desktop/preload.cjs — janela Electron, servidor HTTP local, proxies e instalador Windows.
Pipeline de Seleção de Polígonos
Todo clique em polígono no mapa passa por um pipeline unificado que opera sobre 4 fontes simultâneas com suporte a desambiguação e multi-seleção por Shift.
As 4 fontes de candidatos
geojsonFeatures
Polígonos vetorizados automaticamente pelo pipeline WASM.
manualPolygonFeatures
Polígonos desenhados manualmente pelo usuário com Leaflet.Draw.
Camada de referência (APP)
Shapefile importado gerenciado pelo app-boundary-manager.
Parcelas SIGEF
Features carregadas por consulta WFS ao Acervo Fundiário INCRA.
Helpers do pipeline novos
| Função | Papel |
|---|---|
aplicarSelecaoCandidataNoMapa(item, layer, evt) | Ponto único de despacho após desambiguação ou clique direto; roteia para SIGEF, referência importada ou polígono regular. |
aplicarSelecaoSigefNoMapa(idx, multiSelect) | Toggle de seleção SIGEF com atualização de estilo e chamada a atualizarExportSigefUi(). |
_buscarLayerPorFeatureId(featureId) | Localiza layer Leaflet pelo ID da feature em drawnItems. |
_mostrarDicaMultiSelecao() | Exibe notificação educativa sobre Shift+clique (uma única vez por instalação). |
Variáveis globais críticas
let _selecaoMemorialAtiva = false; // true quando aguardando clique para memorial let _selecaoMemorialClickHandler = null; // handler registrado durante seleção de memorial let selectedFeatureId = null; // feature ativa (single) const selectedFeatureIds = new Set(); // features selecionadas (multi) let sigefSelectedIds = new Set(); // índices SIGEF selecionados let suppressMapClickDeselectUntil = 0; // timestamp para suprimir deselect
vetorizador_multiselect_hint_v1).
Fronteiras Arquiteturais
Contratos que devem ser preservados em qualquer refatoração ou extensão do sistema.
🦀 Fronteira 1 — WASM soberano
vetorizar_imagem continua sendo a única fonte de extração geométrica. O fluxo ativo permanece determinístico (WASM-only). Saída obrigatória: GeoJSON Polygon com anel fechado, coordenadas normalizadas em pixels [0.0, 1.0].
💾 Fronteira 2 — Camada de referência local por instalação
A camada de referência topográfica (APP) permanece local no desktop. No fluxo de memorial SIGEF, exatamente 1 polígono de referência é escolhido por clique (com desambiguação se necessário), com candidatos das 4 fontes disponíveis no mapa.
⚡ Fronteira 3 — CONFIG como contrato central
Parâmetros do pipeline dependem de CONFIG em app.js. Qualquer novo parâmetro precisa refletir: controles de UI, sincronizarControle, aplicarPreset e resetarParametros.
🖥️ Fronteira 4 — Desktop como produto de primeira classe
O instalador Windows não é acessório. O build desktop carrega frontend compilado, endpoints locais e artefatos WASM. Firebase/Firestore foram removidos; toda persistência é local-first.
Padrões de Design GoF
Padrões identificados por contrato reverso no codebase atual.
Singleton
Evidências: app-boundary-manager.js mantém estado da camada de referência em escopo de módulo; CONFIG em app.js é fonte única de parâmetros; cache de módulos dinâmicos em _modulosDinamicos.
AppContext explícito.
Strategy
Evidências: seleção de comportamento por preset (cobertura, uso_solo, manual); guardrails por cenário em geo-postprocess.js; pontuação de cena em scene-classifier.js.
Status de melhoria: PresetManager já extraído com contrato estável. Estratégias de pipeline ainda espalhadas como condicionais em app.js.
Template Method
Evidências: pipeline principal com sequência fixa (captura → Sobel → Otsu → morfologia → DBSCAN → WASM → pós-processamento → exportação); scene-classifier.js com roteiro estável; vetoriza/src/lib.rs com sequência determinística.
Factory Method
Evidências: createAppBoundaryManager(), createFeatureFlagManager(), createPresetManager(deps), createStateManager(), createVectorizationPipeline({ executeCore }) — todos recebem dependências injetadas e retornam instâncias com API pública estável.
Observer
Evidências: listeners de eventos Leaflet (layer.on('click'), map.on('draw:created')); interceptação de console.* pelo sistema de diagnóstico; window.addEventListener para erros globais e beforeunload.
Módulos Core do Frontend
Orquestrador principal (~12 000 linhas)
Inicialização do shell, estado global, pipeline de configuração, integração mapa-WASM-persistência. Pipeline de seleção unificado para 4 fontes. Helpers novos: aplicarSelecaoCandidataNoMapa, aplicarSelecaoSigefNoMapa, _buscarLayerPorFeatureId.
Shell da interface principal
Containers, painéis, botões, modais. Ordem de carregamento: CDN libs → vetoriza/pkg/vetoriza.js → app.js. Modal #seletorPoligonoModal para desambiguação global.
Pós-processamento geométrico
Supressão de redundância geométrica, filtros por área/bbox/IoU, guardrails por preset, refinamento de features. Não depende de DOM.
Classificação de cena
Classifica a cena da ROI para apoiar seleção automática de preset e definir limites de comportamento determinístico por cenário.
Módulos de Suporte
Gerenciador da camada de referência (APP)
Concentra o ciclo de vida da camada de referência topográfica por instalação. Normaliza GeoJSON, persiste cache em localStorage (vetorizador_app_boundary_v2), exibe no mapa. O callback onFeatureClick delega para lidarCliquePoligono tornando a camada participante da desambiguação global.
Gerenciador de feature flags
Flags persistidas em localStorage, guardrails WASM-only, auditoria operacional, BENCHMARK_APROVACAO_PRESET por preset. Inicialização: initFeatureFlagManager({ syncConfigField }).
Gerenciador de presets
PRESET_DEFINITIONS, PRESET_PIPELINE_RULES, PRESET_POLY_QUALITY_DEFAULTS, CONFIG_RESET_DEFAULTS. Factory: createPresetManager(deps). Presets visíveis na UI: cobertura e uso_solo; perfil manual normalizado para cobertura.
Gerenciador de estado de sessão
Centraliza estado mutável da sessão: modoVetorizacao, geojsonFeatures, manualPolygonFeatures, activeRunId, activeRunStartedAt, currentSelectionMaskFeature. Mantém estabilidade de referência dos arrays para compatibilidade de callsites.
Fronteira explícita do pipeline
Factory createVectorizationPipeline({ executeCore }). Expõe processarAreaDesenhada delegando a implementação core para executeCore injetado. Permite evolução do desacoplamento interno sem quebrar a interface pública.
Política de seleção (UX)
Centraliza regras de UX de seleção no mapa. Exporta shouldOpenPopupForSelection({ multiSelect }) — retorna true apenas quando não é Shift+clique. Ponto único de decisão sobre abertura de popup para todas as 4 fontes.
Telemetria de fluxos operacionais
Exporta flowStart(name, details), flowSuccess(name, details) e flowError(name, error) para rastreamento padronizado de início/sucesso/erro de fluxos via window.DIAG?.section('FLOW', ...). Dependência opcional — inerte quando DIAG não está disponível.
Sistema de diagnóstico total
Buffer circular de 8 000 entradas. Módulos internos emitem diretamente via window.DIAG?.* com categorias estruturadas. Cobertura ampliada para importação SIGEF, desambiguação de rótulos, memorial e exportação SHP confrontado (com flowStart/flowSuccess/flowError). Interceptação de console.* captura libs externas como fallback. Archive em IndexedDB, exportação consolidada. API:
DIAG.log(cat, msg, data) // 3 params — SEMPRE DIAG.warn(cat, msg, data) // 3 params DIAG.error(cat, msg, data) // 3 params DIAG.funcEntry(funcName, data) DIAG.uiEvent(element, eventType, details) DIAG.section(cat, name, data)
Desktop & APIs Auxiliares
Runtime desktop (Electron v41)
desktop/main.cjs
Bootstrap Electron, ciclo de vida da aplicação, criação da janela principal, sandbox + contextIsolation.
desktop/app-server.cjs
Servidor HTTP local (porta 3210), exposição do frontend compilado, proxies para WFS INCRA, Nominatim e elevação SRTM.
desktop/preload.cjs
Ponte controlada entre renderer e capacidades do Electron.
Proxies do backend local
| Endpoint | Destino real | Motivo do proxy |
|---|---|---|
/api/proxy/nominatim-reverse | nominatim.openstreetmap.org | CORS/CSP no renderer |
/api/proxy/nominatim-search | nominatim.openstreetmap.org | CORS/CSP no renderer |
/api/proxy/incra-wfs | WFS SIGEF INCRA por UF | CORS/CSP no renderer |
/api/proxy/elevation | api.opentopodata.org (SRTM 30m) | CORS/CSP no renderer |
/api/pdf-to-geojson | — (local) | OCR + parser local |
/api/shp-to-geojson | — (local) | Conversão shapefile |
/api/sigef-imoveis | — (local) | Consulta e download SIGEF WFS |
SIGEF & Memorial (módulos independentes)
sigef-wfs.js
Consulta WFS público INCRA, detecção automática de UF pela ROI, normalização GeoJSON, roteamento pelo proxy desktop.
sigef-memorial.js
Comparação de vértices (haversine 5 m), herança de coordenadas SIGEF, cota Z via SRTM, geração de DOCX e exportação SHP confrontado.
Fluxo de Vetorização Automática
Localizar e capturar
Busca por endereço (Nominatim) ou coordenada. Desenho da ROI com Leaflet.Draw.
Pré-processar imagem
Realce de contraste (contrastBoost), Sobel, Otsu, morfologia (morphologySize), DBSCAN opcional (clusterEps, clusterMinPts).
vetorizar_imagem (WASM)
Base64 PNG → núcleo Rust → FeatureCollection GeoJSON em pixel-space [0,1].
Pós-processamento geométrico
geo-postprocess.js: NMS, filtro por área/bbox/IoU, guardrails por preset, simplificação, regularização.
Conversão pixel → coordenada
Transformação de pixel-space para lat/lng com base nos bounds da ROI.
Revisão visual + exportação
Polígonos exibidos no mapa com código de cor por qualidade. Exportação GeoJSON, Shapefile, relatório APP.
Confrontação SIGEF & Memorial Descritivo
Consulta WFS SIGEF
UF detectada automaticamente pela ROI. Requisição via proxy local /api/proxy/incra-wfs. Parcelas carregadas como camada Leaflet selecionável.
Carregar imóvel de referência
Shapefile compactado ZIP → conversão local → app-boundary-manager. Cache em vetorizador_app_boundary_v2.
Modo de seleção de referência
_selecaoMemorialAtiva = true, cursor crosshair. Clique no mapa ativa _selecaoMemorialClickHandler. Candidatos: 4 fontes de polígono. Sobreposição → modal de desambiguação.
Confronto de vértices
Haversine ≤ 5 m → vértice certificado (herda coordenadas SIGEF, prefixo do campo rt/RT). Haversine > 5 m → vértice novo (prefixo NV-001).
Cota Z
Prioridade: metadados SIGEF → coord[2] do polígono → SRTM 30m via /api/proxy/elevation. coord[2] === 0 tratado como ausente. Campo altitudeSource: SIGEF, POLIGONO_CARREGADO ou SRTM.
Geração e exportação
Memorial DOCX com azimute, distância (haversine), área geodésica (ha) e cota Z por vértice. SHP confrontado com campos COTA_N_MIN/MAX/MED, COTA_S_MIN/MAX/MED e COTA_FONTE.
Math.hypot em graus → 0,00 m); área geodésica (era signedArea em graus → 0,00 ha); tolerância de certificação (era 0,00005° ≈ 0,05 mm → agora 5 m); Z=0 do WFS tratado como ausente.
Desambiguação Global de Sobreposição
Quando um clique no mapa intercepta 2 ou mais polígonos de qualquer fonte, o modal de desambiguação é acionado automaticamente para garantir escolha explícita.
Lógica de escolherComDesambiguacaoGlobal()
Promise-based. Recebe array de candidatos { key, source, feature, label, featureId?, boundaryIdx?, featureIdx? }, ordena por área crescente (menor = mais específico primeiro) e exibe swatches de cor 44×44 px em grid. Cancela com reject(); escolha com resolve(item).
DIAG registra 3 fases: modal-aberto, escolhido e cancelado.
Estilo de seleção
aplicarEstiloSelecao(baseStyle, isSelected) retorna: color: '#00e5ff', weight+2, opacity: 1, dashArray: null (sem tracejado — borda sólida).
SIGEF selecionado: SIGEF_STYLE_SELECTED = { color: '#b71c1c', fillColor: '#ef5350', fillOpacity: 0.50, weight: 3 }.
Snap & Auto-vertex por Shift
Durante o desenho de polígonos de atributos, pontos magnéticos de snap são exibidos. Segurar Shift ativa inserção automática de vértices a cada ponto detectado.
Variáveis de controle
let _snapShiftAutoActive = false; // Shift pressionado = auto-inserção ativa let _snapLastAutoPoint = null; // último ponto auto-inserido (deduplicação)
Ciclo de vida
mousemove
Se _snapShiftAutoActive && snap && snap !== _snapLastAutoPoint → insere vértice automaticamente e atualiza _snapLastAutoPoint.
keydown Shift
_snapShiftAutoActive = true. Hint atualizado: "Segure Shift = auto-snap". Cliques ignorados enquanto Shift estiver pressionado (evita duplicata).
keyup Shift
_snapShiftAutoActive = false. Retorna ao modo manual.
_pararDesenhoPoligonoAtributos()
Remove listener keyup, reinicia _snapShiftAutoActive = false e _snapLastAutoPoint = null.
CONFIG & Estado de Sessão
Estrutura CONFIG (app.js)
Fonte única de parâmetros do pipeline. Todo novo campo exige atualização em 4 lugares.
| Campo | Tipo | Papel |
|---|---|---|
edgeThreshold | number | Limiar de borda Sobel/Otsu |
morphologySize | number | Kernel de morfologia (closing) |
minArea | number | Área mínima candidata (pixels) |
simplification | number | Tolerância Douglas-Peucker |
contrastBoost | number | Fator de amplificação de contraste |
minQualityScore | number | Score mínimo para aceite |
mergeDistance | number | Distância de fusão |
clusteringEnabled | boolean | Habilita agrupamento DBSCAN |
clusterEps | number | Raio DBSCAN |
clusterMinPts | number | Densidade mínima DBSCAN |
presetProfile | string | Perfil ativo |
Estado de sessão (state-manager.js)
| Campo | Tipo | Papel |
|---|---|---|
modoVetorizacao | 'auto'|'manual' | Modo operacional ativo |
geojsonFeatures | array | Features de vetorização automática |
manualPolygonFeatures | array | Features de desenho manual |
activeRunId | string/null | ID da execução corrente |
currentSelectionMaskFeature | Feature/null | Máscara de seleção ativa |
Persistência Local
IndexedDB — vetorizador_learning_db
runs
Snapshot de execução: bounds, config, relatório, features. Apenas execuções modoVetorizacao = auto.
feedback
Validações do usuário e marcações de qualidade por feature. Índices: runId e featureId.
IndexedDB — vetorizador_diagnostic_archive_db
entries
Eventos de diagnóstico por sequência. Retenção controlada em modo session-only.
sessions
Metadados de sessão de diagnóstico. Máx. 4 sessões + 24h de retenção.
Chaves localStorage
| Chave | Módulo | Propósito |
|---|---|---|
vetorizador_app_boundary_v2 | app-boundary-manager | Cache da camada de referência (APP) |
vetorizador_app_boundary_v1 | app-boundary-manager | Chave legada — lida apenas para migração automática para _v2 |
vetorizador_feature_flags_v1 | feature-flag-manager | Feature flags persistidas |
vetorizador_backend_refine_audit_v1 | feature-flag-manager | Auditoria operacional de flags |
vetorizador_assist_telemetry_v1 | app.js | Telemetria leve de uso |
vetorizador_multiselect_hint_v1 | app.js | Flag notificação educativa Shift multi-select |
Contrato WASM
Interface formal da função exportada pelo módulo Rust vetoriza/src/lib.rs.
Assinatura
vetorizar_imagem(base64_png: string) → string // JSON serializado
| Parâmetro | Tipo | Descrição |
|---|---|---|
base64_png | string | PNG codificado Base64, sem prefixo data URI. Deve ser escala de cinza, sem alpha, pré-processado. |
Saída — FeatureCollection GeoJSON
{
"type": "FeatureCollection",
"features": [{
"type": "Feature",
"geometry": {
"type": "Polygon",
"coordinates": [[[lon, lat], ..., [lon, lat]]]
},
"properties": {}
}]
}
Invariantes garantidos
Anel fechado
Último ponto = primeiro ponto. Sempre.
Sem furos
Cada Polygon tem exatamente um anel externo.
Pixel-space [0, 1]
Coordenadas normalizadas. Conversão para lat/lng em app.js.
Inicialização
// index.html — ordem crítica <script src="vetoriza/pkg/vetoriza.js"></script> // app.js await wasm_bindgen(wasmUrl); vetorizar_imagem = wasm_bindgen.vetorizar_imagem;
Rebuild WASM após mudanças em vetoriza/src/lib.rs: wasm-pack build --target no-modules --release
Sistema de Diagnóstico
Capacidades
Buffer circular
8 000 entradas em memória com sequência, timestamp e categoria.
Telemetria direta
Módulos internos chamam window.DIAG?.* diretamente (186 call sites). console.* interceptado como fallback para libs externas (Leaflet, Turf, shpwrite).
Archive IndexedDB
Flush periódico para vetorizador_diagnostic_archive_db. Retenção session-only, máx. 4 sessões.
Exportação consolidada
Botão único exporta: buffer + archive + contexto expandido em JSON auditável offline.
Categorias de log registradas
DIAG.log() aceita exatamente 3 parâmetros (category, message, data). Chamadas com 4 parâmetros são incorretas e devem ser corrigidas.
Rastreabilidade de Requisitos Funcionais
Referência: Abril 2026 · Branch win-desktop-main
| ID | Nome | Status | Módulo |
|---|---|---|---|
| RF-01 | Busca cartográfica | Implementado | app.js → Nominatim |
| RF-03 | Delimitação da ROI | Implementado | app.js, Leaflet.Draw |
| RF-04 | Alternância de modo | Implementado | state-manager.js |
| RF-06 | Seleção de preset | Implementado | preset-manager.js |
| RF-09 | Pré-processamento da imagem | Implementado | vectorization-pipeline.js |
| RF-10 | Agrupamento DBSCAN | Implementado | app.js |
| RF-11 | Vetorização determinística | Implementado | vetoriza/src/lib.rs |
| RF-12 | Pós-processamento geométrico | Implementado | geo-postprocess.js |
| RF-13 | Operação WASM-only | Parcial | feature-flag-manager.js |
| RF-16 | Exportação GeoJSON | Implementado | app.js |
| RF-17 | Exportação Shapefile | Implementado | app.js, shpwrite |
| RF-19 | Camada de referência | Implementado | app-boundary-manager.js |
| RF-20 | Persistência local runs | Implementado | IndexedDB vetorizador_learning_db |
| RF-23 | Operação sem autenticação | Implementado | app.js, app-boundary-manager.js |
| RF-25 | Resiliência offline | Implementado | IndexedDB + localStorage |
| RF-26 | Módulo PDF | Implementado | pdfspliter/ via iframe |
| RF-28 | Runtime desktop | Implementado | desktop/main.cjs |
| RF-30 | Telemetria e auditoria | Parcial | diagnostic-logger.js |
Requisitos Não Funcionais
| ID | Nome | Status | Observação |
|---|---|---|---|
| RNF-01 | Consistência geométrica | Implementado | Polígonos fechados garantidos pelo WASM |
| RNF-02 | Determinismo do núcleo | Implementado | WASM como única fonte de extração |
| RNF-03 | Desempenho operacional | Parcial | Meta < 60s/imagem documentada; sem benchmark automatizado formal |
| RNF-04 | Qualidade mínima | Parcial | F1 ≥ 0,70 e IoU ≥ 0,60 definidos; sem regressão automatizada |
| RNF-05 | Continuidade offline | Implementado | Fluxos locais independentes de conectividade |
| RNF-07 | Observabilidade | Implementado | 186 call sites migrados para window.DIAG?.*; categorias APP, GEO, SCENE, PRESET, BOUNDARY; fallback para libs externas |
| RNF-08 | Portabilidade | Implementado | Runtime Electron para Windows (desktop) |
| RNF-10 | Manutenibilidade | Implementado | 5 módulos extraídos; desacoplamento fino fase 2 pendente |
| RNF-11 | Segurança operacional | Implementado | Dados sensíveis permanecem locais no desktop |
| RNF-14 | Auditabilidade | Implementado | Logs de decisão, auditoria de flags, telemetria local |
Evolução & Escala
Etapas de modularização
| Etapa | Status | Descrição |
|---|---|---|
| Etapa 1 — Modularização | Concluída | 5 módulos extraídos de app.js: AppBoundaryManager, FeatureFlagManager, PresetManager, StateManager, VectorizationPipeline |
| Etapa 1 fase 2 | Pendente | StateManager fase 2 (callsites remanescentes); VectorizationPipeline fase 2 (extração do core por subetapas) |
| Etapa 2 — Contratos | Concluída | 4 contratos em docs/contratos/: wasm-contract, storage-keys, api-schemas, app-boundary |
| Etapa 3 — Observabilidade | Concluída | 186 call sites migrados para window.DIAG?.* com categorias estruturadas; telemetria direta sem DevTools; exportação consolidada no painel lateral desktop |
O que precisa ser protegido
WASM soberano
O pipeline principal precisa continuar operável e auditável com o WASM como fonte de extração geométrica.
Desktop relevante
Canal de distribuição ativo. Build desktop deve continuar levando WASM + frontend + APIs locais.
Local-first
Persistência local prioritária. Sem dependências de autenticação ou sincronização remota no fluxo operacional.
APP por instalação
Camada de referência topográfica permanece local por instalação no desktop.
Principais passivos arquiteturais
window.*.
Build & Runbooks
Comandos principais
npm install # instalar dependências npm run dev # servidor de desenvolvimento Vite npm run lint # ESLint npm run build # build produção npm run preview # preview do build npm run desktop:dev # Electron + Vite em desenvolvimento npm run desktop:start # Electron sobre build existente npm run dist:win # empacotamento Windows (.exe)
Rebuild do WASM
Sempre que houver mudança em vetoriza/src/lib.rs:
cd vetoriza wasm-pack build --target no-modules --release
Após o rebuild, validar novamente o build do frontend com npm run lint && npm run build.
Runbooks de diagnóstico rápido
Build falha
Verificar: erros de lint → warnings do bundler → artefatos WASM ausentes → type="module" no Vite → node_modules.
WASM não carrega
Verificar: presença de vetoriza/pkg/vetoriza.js e vetoriza_bg.wasm → ordem de script → disponibilidade de wasm_bindgen.vetorizar_imagem.
API local falha
Verificar: desktop/app-server.cjs → portas ocupadas → api/local.settings.json → endpoints de health.
SIGEF não carrega
Verificar: disponibilidade do WFS INCRA por UF → proxy /api/proxy/incra-wfs → metadados de consulta em sigefQueryMetadata.
npm run dev → validar com npm run lint && npm run build → testar desktop com npm run desktop:dev → empacotar com npm run dist:win.