<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Documentação Técnica App + API REST - Parte 1]]></title><description><![CDATA[<h1><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f4d6.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--book" title=":book:" alt="📖" /> Documentação Técnica — Insoft QFace App</h1>
<blockquote>
<p dir="auto"><strong>Versão:</strong> 1.0.0<br />
<strong>Empresa:</strong> Insoft4 Informática LTDA<br />
<strong>Plataforma:</strong> Windows (x64 / ia32)<br />
<strong>Data:</strong> Abril de 2026</p>
</blockquote>
<hr />
<h1><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f4cc.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--pushpin" title=":pushpin:" alt="📌" /> 1. VISÃO GERAL DO SISTEMA</h1>
<h2>O que é este sistema?</h2>
<p dir="auto">O <strong>Insoft QFace App</strong> é um software desktop para Windows desenvolvido pela Insoft4 Informática. Ele serve como <strong>interface gráfica e gerenciador</strong> de um leitor biométrico facial da linha <strong>QFace (Digicon/Suprema)</strong>.</p>
<h3>Problema que resolve</h3>
<p dir="auto">Empresas que utilizam leitores biométricos faciais QFace precisam:</p>
<ul>
<li>Cadastrar imagens faciais de colaboradores no dispositivo</li>
<li>Converter imagens (JPEG/PNG) em <strong>templates biométricos</strong> (dados compactados que representam o rosto da pessoa)</li>
<li>Capturar fotos ao vivo usando a câmera do dispositivo QFace</li>
<li>Gerenciar o serviço de API que realiza estas operações</li>
<li>Monitorar o status da API e do dispositivo em tempo real</li>
</ul>
<h3>Público-alvo</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Público</th>
<th>Uso principal</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Administradores de TI</strong></td>
<td>Instalar, configurar e gerenciar o serviço</td>
</tr>
<tr>
<td><strong>Operadores</strong></td>
<td>Monitorar conversões e capturas em andamento</td>
</tr>
<tr>
<td><strong>Desenvolvedores</strong></td>
<td>Integrar sistemas externos via REST API</td>
</tr>
<tr>
<td><strong>Suporte Técnico</strong></td>
<td>Diagnosticar falhas e consultar logs</td>
</tr>
</tbody>
</table>
<h3>Principais funcionalidades</h3>
<ul>
<li><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--white_check_mark" title=":white_check_mark:" alt="✅" /> Conversão de imagens faciais em templates biométricos (via QFace SDK)</li>
<li><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--white_check_mark" title=":white_check_mark:" alt="✅" /> Captura ao vivo pela câmera do dispositivo QFace</li>
<li><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--white_check_mark" title=":white_check_mark:" alt="✅" /> Dashboard de monitoramento (status da API e do dispositivo)</li>
<li><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--white_check_mark" title=":white_check_mark:" alt="✅" /> Gerenciamento do serviço Windows (<code>insoft-qface-win-api</code>)</li>
<li><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--white_check_mark" title=":white_check_mark:" alt="✅" /> Configuração de conexão com o dispositivo (IP, porta)</li>
<li><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--white_check_mark" title=":white_check_mark:" alt="✅" /> Suporte a SSL/TLS para a API REST</li>
<li><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--white_check_mark" title=":white_check_mark:" alt="✅" /> Integração com API externa (webhook de saída configurável)</li>
<li><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--white_check_mark" title=":white_check_mark:" alt="✅" /> Histórico de conversões realizadas</li>
<li><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--white_check_mark" title=":white_check_mark:" alt="✅" /> Logs de operação em arquivo</li>
</ul>
<hr />
<h1><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f3d7.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--building_construction" title=":building_construction:" alt="🏗" />️ 2. ARQUITETURA DO SISTEMA</h1>
<h2>Visão simplificada (para Suporte)</h2>
<p dir="auto">O sistema é composto por <strong>dois programas</strong> que trabalham juntos:</p>
<pre><code>┌──────────────────────────────────────────────┐
│         INSOFT QFACE APP (.exe)              │
│  Interface gráfica + Gerenciador (Electron)  │
│                                              │
│   ┌──────────────────┐                       │
│   │   React (UI)     │ ← Usuário interage    │
│   └────────┬─────────┘                       │
│            │ IPC (comunicação interna)        │
│   ┌────────▼─────────┐                       │
│   │  Electron Main   │ ← Controla tudo       │
│   └────────┬─────────┘                       │
└────────────┼─────────────────────────────────┘
             │ WebSocket (porta 3133)
             │ HTTP REST (porta 3333)
┌────────────▼─────────────────────────────────┐
│      INSOFT QFACE WIN API (.exe)             │
│    Servidor REST + Integração com SDK        │
│                                              │
│   ┌──────────────────┐                       │
│   │  Express Server  │ ← Recebe requisições  │
│   └────────┬─────────┘                       │
│            │                                  │
│   ┌────────▼─────────┐                       │
│   │   QFace SDK      │ ← Fala com o leitor   │
│   │  (DLL nativa)    │                       │
│   └──────────────────┘                       │
└──────────────────────────────────────────────┘
             │
             │ TCP/IP (porta 12120)
             ▼
    ┌─────────────────┐
    │  Dispositivo    │
    │  QFace (leitor) │
    │  Digicon/Suprema│
    └─────────────────┘
</code></pre>
<h2>Arquitetura técnica</h2>
<p dir="auto">O projeto utiliza uma arquitetura em camadas com separação clara de responsabilidades:</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Camada</th>
<th>Tecnologia</th>
<th>Responsabilidade</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>UI (Frontend)</strong></td>
<td>React + TypeScript + Tailwind CSS</td>
<td>Interface visual do usuário</td>
</tr>
<tr>
<td><strong>Desktop Shell</strong></td>
<td>Electron (Node.js + Chromium)</td>
<td>Janela nativa Windows, IPC, gerenciamento de sistema</td>
</tr>
<tr>
<td><strong>API REST</strong></td>
<td>Express.js + TypeScript</td>
<td>Endpoints HTTP para operações biométricas</td>
</tr>
<tr>
<td><strong>SDK Wrapper</strong></td>
<td>Koffi (FFI) + DLL nativa</td>
<td>Comunicação com o hardware QFace via DLL C/C++</td>
</tr>
<tr>
<td><strong>Serviço Windows</strong></td>
<td>NSSM (Non-Sucking Service Manager)</td>
<td>Execução do API como serviço do Windows</td>
</tr>
<tr>
<td><strong>Comunicação em tempo real</strong></td>
<td><a href="http://Socket.IO" rel="nofollow ugc">Socket.IO</a></td>
<td>Notificações de eventos entre API e interface</td>
</tr>
</tbody>
</table>
<h2>Como os componentes se comunicam</h2>
<pre><code>React UI
   │
   ├─── contextBridge (window.electron.*) ──► Preload.ts ──► ipcMain (IPC canais)
   │                                                               │
   │                                                        main.ts / ipc/index.ts
   │                                                               │
   │                                             ┌────────────────┼─────────────────┐
   │                                             │                │                 │
   │                                     HTTP Requests    WebSocket Client   Windows SC
   │                                             │                │
   │                                    insoft-qface-win-api      │
   │                                             │                │
   │                                     Express Routes     Socket.IO Server
   │                                             │              (porta 3133)
   │                                      Controller
   │                                             │
   │                                        QFace SDK (DLL)
   │                                             │
   └──────────────────────── Dispositivo QFace (IP:12120)
</code></pre>
<h2>Tecnologias utilizadas</h2>
<h3><code>insoft-qface-app</code> (Frontend + Electron)</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Tecnologia</th>
<th>Versão</th>
<th>Finalidade</th>
</tr>
</thead>
<tbody>
<tr>
<td>Electron</td>
<td>^30.0.1</td>
<td>Shell desktop nativo</td>
</tr>
<tr>
<td>React</td>
<td>^18.3.1</td>
<td>Interface do usuário</td>
</tr>
<tr>
<td>TypeScript</td>
<td>^5.2.2</td>
<td>Tipagem estática</td>
</tr>
<tr>
<td>Vite</td>
<td>^5.1.4</td>
<td>Build do frontend</td>
</tr>
<tr>
<td>Tailwind CSS</td>
<td>^3.4.3</td>
<td>Estilização</td>
</tr>
<tr>
<td>Flowbite React</td>
<td>0.12.9</td>
<td>Componentes UI</td>
</tr>
<tr>
<td><a href="http://Socket.IO" rel="nofollow ugc">Socket.IO</a> Client</td>
<td>^4.8.1</td>
<td>Comunicação em tempo real com a API</td>
</tr>
<tr>
<td>React Router</td>
<td>^6.26.2</td>
<td>Navegação entre telas</td>
</tr>
<tr>
<td>React Hook Form</td>
<td>^7.56.2</td>
<td>Formulários</td>
</tr>
<tr>
<td>Zod</td>
<td>^3.24.4</td>
<td>Validação de schemas</td>
</tr>
<tr>
<td>electron-log</td>
<td>^5.2.4</td>
<td>Logs persistentes</td>
</tr>
<tr>
<td>electron-store</td>
<td>^9.0.0</td>
<td>Armazenamento local</td>
</tr>
</tbody>
</table>
<h3><code>insoft-qface-win-api</code> (API Backend)</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Tecnologia</th>
<th>Versão</th>
<th>Finalidade</th>
</tr>
</thead>
<tbody>
<tr>
<td>Node.js</td>
<td>18 (target)</td>
<td>Runtime</td>
</tr>
<tr>
<td>Express</td>
<td>^5.1.0</td>
<td>Servidor HTTP</td>
</tr>
<tr>
<td>TypeScript</td>
<td>^5.2.2</td>
<td>Tipagem estática</td>
</tr>
<tr>
<td>Koffi</td>
<td>^2.8.0</td>
<td>Binding FFI para DLL nativa</td>
</tr>
<tr>
<td><a href="http://Socket.IO" rel="nofollow ugc">Socket.IO</a></td>
<td>^4.8.1</td>
<td>Eventos em tempo real</td>
</tr>
<tr>
<td>Helmet</td>
<td>^8.1.0</td>
<td>Segurança HTTP</td>
</tr>
<tr>
<td>Morgan</td>
<td>^1.10.1</td>
<td>Logs de requisições</td>
</tr>
<tr>
<td>pkg</td>
<td>^5.8.1</td>
<td>Empacotamento em .exe standalone</td>
</tr>
</tbody>
</table>
<hr />
<h1><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f4c1.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--file_folder" title=":file_folder:" alt="📁" /> 3. ESTRUTURA DE PASTAS E COMPONENTES</h1>
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f4c2.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--open_file_folder" title=":open_file_folder:" alt="📂" /> Raiz do Monorepo (<code>insoft-qface-global-app/</code>)</h2>
<pre><code>insoft-qface-global-app/
├── insoft-qface-app/      ← Aplicativo Electron (Desktop)
├── insoft-qface-win-api/  ← Servidor REST API (Windows)
└── shared/
    └── i18n/              ← Mensagens e códigos internacionalizados
</code></pre>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f4c2.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--open_file_folder" title=":open_file_folder:" alt="📂" /> <code>insoft-qface-app/</code> — Aplicativo Desktop</h2>
<p dir="auto"><strong>Descrição funcional (para Suporte):</strong></p>
<blockquote>
<p dir="auto">Este é o programa principal que o usuário vê e usa. Ele exibe a interface gráfica, controla o serviço de API em segundo plano e se comunica com a janela do Windows.</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica (para Devs):</strong></p>
<pre><code>insoft-qface-app/
├── electron/
│   └── main/
│       ├── main.ts              ← Ponto de entrada do processo principal do Electron
│       ├── preload.ts           ← Bridge segura entre Renderer (React) e Main process
│       ├── CertificateStore.ts  ← Gerenciamento de certificado SSL no Windows
│       ├── types.d.ts           ← Tipos TypeScript globais
│       ├── i18n/
│       │   └── messages.ts      ← Constantes de mensagens (códigos i18n)
│       ├── ipc/
│       │   ├── index.ts         ← Handlers IPC para Dashboard, Device, API management
│       │   └── ui-actions.ts    ← Handlers IPC para ações de UI (janela, tema)
│       └── utils/
│           ├── logger.ts              ← Configuração do electron-log
│           ├── nssm-manager.ts        ← Operações com NSSM (install/start/stop/status)
│           └── windows-service-manager.ts ← Wrapper para gerenciar serviços Windows
├── src/
│   ├── App.tsx                  ← Componente raiz React
│   ├── routes/
│   │   ├── AppRoutes.tsx        ← Definição de todas as rotas da aplicação
│   │   ├── ContextRoutes.tsx    ← Wrapper de rotas com contexto (MainView)
│   │   └── NavigationListener.tsx ← Escuta eventos de navegação do IPC
│   ├── context/
│   │   ├── ConfigContext.tsx    ← Contexto global de configurações
│   │   └── ThemeContext.tsx     ← Contexto de tema (dark/light)
│   ├── hooks/
│   │   ├── useApiServiceStatus.ts ← Hook para status do serviço Windows
│   │   ├── useCamera.ts           ← Hook para acesso à câmera
│   │   └── useDarkMode.ts         ← Hook para alternância de tema
│   ├── mappings/
│   │   ├── AppSettings.ts       ← Interface TypeScript das configurações
│   │   └── types.ts             ← Tipos compartilhados do frontend
│   ├── views/
│   │   ├── StartApp/            ← Tela inicial (verificação de serviço)
│   │   ├── Dashboard/           ← Painel de monitoramento
│   │   ├── ApiManagement/       ← Gerenciamento da API e fluxo de conversão/captura
│   │   ├── DeviceManagement/    ← Gerenciamento do dispositivo QFace
│   │   ├── Settings/            ← Configurações do sistema
│   │   └── MainView/            ← Layout principal (menu lateral + header)
│   ├── components/              ← Componentes reutilizáveis (Button, Card, Modal, etc.)
│   └── utils/                   ← Utilitários (captureFrame, getQualityStyle, etc.)
├── config/
│   └── application.json         ← Arquivo de configuração principal (editável)
├── nssm/
│   ├── win32/                   ← NSSM para x86
│   └── win64/                   ← NSSM para x64
├── cert_app/                    ← Certificado digital da aplicação
└── electron-builder.json        ← Configurações de build/empacotamento
</code></pre>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f4c2.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--open_file_folder" title=":open_file_folder:" alt="📂" /> <code>insoft-qface-win-api/</code> — API REST Windows</h2>
<p dir="auto"><strong>Descrição funcional (para Suporte):</strong></p>
<blockquote>
<p dir="auto">Este é o "motor" que faz as operações reais com o leitor QFace. Ele fica rodando em segundo plano como um Serviço do Windows (similar ao antivírus), recebe comandos da interface gráfica e se comunica diretamente com o hardware biométrico.</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica (para Devs):</strong></p>
<pre><code>insoft-qface-win-api/
├── src/
│   ├── start.ts                    ← Ponto de entrada do servidor
│   ├── server/
│   │   ├── index.ts                ← Configuração Express, Socket.IO, HTTPS/HTTP, Mutex
│   │   ├── routes.ts               ← Agregador de rotas (picture + device)
│   │   └── eventQueue.ts           ← Fila de eventos para comunicação com Electron
│   ├── routes/
│   │   ├── pictureRoutes.ts        ← Rotas: /v1/foto/converter, /v1/foto/capturar, /internal/*
│   │   └── deviceRoutes.ts         ← Rotas: /v1/qfaceInfo, /device/*
│   ├── controller/
│   │   ├── biometricTemplateController.ts ← Lógica de conversão e captura biométrica
│   │   ├── deviceController.ts     ← Lógica de controle do dispositivo QFace
│   │   └── pendingRequests.ts      ← Map de requisições de captura pendentes
│   ├── sdk/
│   │   └── qface-sdk.ts            ← Wrapper TypeScript para a DLL QFM_SDK_DLL.dll
│   ├── config/
│   │   └── configManager.ts        ← Leitura/escrita do application.json
│   ├── middleware/
│   │   └── auth.ts                 ← Middleware de autenticação Bearer (preparado)
│   ├── i18n/
│   │   └── messages.ts             ← Importa códigos de mensagem do shared/i18n
│   └── utils/
│       ├── logger.ts               ← Configuração de logger
│       └── cameraDeviceName.ts     ← Detecção de câmera no Windows
├── dlls/                           ← DLLs nativas do QFace SDK
├── config/
│   └── application.json            ← Configuração compartilhada
└── scripts/
    └── copy-dlls.js                ← Script de build: copia DLLs para pasta de output
</code></pre>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f4c2.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--open_file_folder" title=":open_file_folder:" alt="📂" /> <code>shared/i18n/</code> — Mensagens Internacionalizadas</h2>
<p dir="auto"><strong>Descrição funcional (para Suporte):</strong></p>
<blockquote>
<p dir="auto">Contém todas as mensagens do sistema traduzidas. Se uma mensagem de erro aparecer com o código <code>repp.message.XXX</code>, consulte este arquivo para ver o texto correspondente.</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica (para Devs):</strong></p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Arquivo</th>
<th>Conteúdo</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>message-codes.json</code></td>
<td>Mapeamento de constantes → códigos (ex: <code>"FAILED_CONNECT_DEVICE": "repp.message.24"</code>)</td>
</tr>
<tr>
<td><code>en-US.json</code></td>
<td>Traduções em Inglês</td>
</tr>
<tr>
<td><code>pt-BR.json</code></td>
<td>Traduções em Português</td>
</tr>
<tr>
<td><code>validate-i18n.mjs</code></td>
<td>Script de validação de consistência entre arquivos de tradução</td>
</tr>
</tbody>
</table>
<p dir="auto">As mensagens são traduzidas automaticamente no <code>preload.ts</code> antes de chegar ao frontend (padrão regex <code>/^repp\.message\.\d+$/</code>).</p>
<hr />
<h1><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f504.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--arrows_counterclockwise" title=":arrows_counterclockwise:" alt="🔄" /> 4. FLUXOS PRINCIPAIS DO SISTEMA</h1>
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f539.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_blue_diamond" title=":small_blue_diamond:" alt="🔹" /> Fluxo 1: Inicialização do Sistema</h2>
<p dir="auto"><strong>Explicação simplificada (Suporte):</strong></p>
<blockquote>
<p dir="auto">Quando o usuário abre o aplicativo, ele automaticamente tenta iniciar o serviço da API em segundo plano. Se o serviço já estiver instalado e rodando, conecta a ele. Se não, tenta iniciá-lo.</p>
</blockquote>
<p dir="auto"><strong>Explicação técnica (Dev):</strong></p>
<pre><code>1. Electron inicia (main.ts)
   ├── Lê config/application.json
   ├── Aplica flags de linha de comando (MediaFoundation, autoplay)
   ├── Instala certificado digital via CertificateStore.ensureInstalled()
   ├── Cria BrowserWindow com preload.ts
   ├── Carrega o React (hash router: /#/)
   └── Chama startApiServer()

2. startApiServer()
   ├── Sonda a API (HTTP GET em /insoft-qface-win-api/v1/health)
   │   ├── Se responder → registra como running, conecta WebSocket
   │   └── Se não responder →
   │       ├── [Windows Prod] Verifica serviço Windows (sc qc insoft-qface-win-api)
   │       │   ├── Instalado → startWindowsService() → espera healthcheck (até 15s)
   │       │   └── Não instalado → exibe erro
   │       └── [Dev] Procura .exe e executa via spawn()

3. connectWebSocket()
   └── Conecta Socket.IO ao localhost:3133 com reconexão infinita
</code></pre>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f539.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_blue_diamond" title=":small_blue_diamond:" alt="🔹" /> Fluxo 2: Conversão de Imagens em Templates Biométricos</h2>
<p dir="auto"><strong>Explicação simplificada (Suporte):</strong></p>
<blockquote>
<p dir="auto">Um sistema externo (ou o próprio usuário) envia imagens faciais para a API. O sistema conecta no leitor QFace, converte cada imagem em um "código biométrico" (template) e retorna esses dados. Durante o processo, a tela do aplicativo abre automaticamente para mostrar o progresso.</p>
</blockquote>
<p dir="auto"><strong>Fluxo detalhado:</strong></p>
<pre><code>Sistema Externo
   │
   │  POST /v1/foto/converter
   │  Body: { "pictures": [{ "personId": 123, "image": "&lt;base64&gt;" }] }
   │
   ▼
insoft-qface-win-api (Express)
   │
   ├── pictureRoutes → convertBiometricTemplate()
   │
   ├── [1] Adquire mutex (garante que apenas 1 conversão ocorre por vez)
   │
   ├── [2] Conecta ao dispositivo QFace via SDK (initSocket)
   │
   ├── [3] Emite evento WebSocket → api:convert:start
   │         └─► Electron main.ts (recebe via Socket.IO)
   │                  └─► mainWindow.webContents.send('api:convert:start')
   │                           └─► React (navega para /api/convert)
   │
   ├── [4] QF_DeleteAll() — apaga templates existentes no dispositivo
   │
   ├── [5] Para cada imagem (sequencial):
   │   ├── Decodifica base64 → Buffer
   │   ├── QF_EnrollImage(userID, imageBuffer) — envia imagem ao dispositivo
   │   ├── QF_ReadTemplate(userID) — lê o template gerado
   │   ├── Converte buffer → string hexadecimal
   │   ├── Salva imagem em imagens/face_&lt;id&gt;.jpeg
   │   ├── Salva template em templates/bio_&lt;id&gt;.tmp
   │   ├── Salva metadados em templates/capture_&lt;id&gt;.json
   │   └── Emite evento WebSocket → api:convert:item (status individual)
   │
   ├── [6] Fecha conexão com dispositivo (closeSocket)
   │
   ├── [7] Emite evento WebSocket → api:convert:done (resultados finais)
   │
   └── [8] Retorna HTTP 200 com array de resultados
</code></pre>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f539.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_blue_diamond" title=":small_blue_diamond:" alt="🔹" /> Fluxo 3: Captura de Foto ao Vivo (QFace Camera)</h2>
<p dir="auto"><strong>Explicação simplificada (Suporte):</strong></p>
<blockquote>
<p dir="auto">Um sistema externo solicita a captura de uma foto usando a câmera do leitor QFace. O aplicativo abre automaticamente a tela de captura, aciona o leitor, o usuário deve ficar na frente do leitor para a foto ser tirada. Quando capturada, o resultado é retornado para o sistema solicitante.</p>
</blockquote>
<p dir="auto"><strong>Fluxo detalhado:</strong></p>
<pre><code>Sistema Externo
   │
   │  POST /v1/foto/capturar
   │  Body: { "personId": 123 }
   │
   ▼
insoft-qface-win-api
   ├── [1] Valida personId/employeeId
   ├── [2] Sonda disponibilidade do QFace (probeQFaceDeviceAvailability)
   │       └─► Se indisponível → retorna 503 imediatamente
   │
   ├── [3] Gera requestId único
   ├── [4] Emite evento WebSocket → api:capture:start { requestId, personId }
   │         └─► Electron main.ts
   │                  ├─► bringWindowToFront() — traz janela para frente
   │                  ├─► navega para /api/capture
   │                  └─► 100ms depois → mainWindow.webContents.send('api:capture:start')
   │
   ├── [5] Registra request em pendingCaptureRequests (Map com Response + timeout)
   │
   └── [6] Aguarda resposta do Electron (timeout configurável, padrão ~60s)
              │
              ▼
         React (PictureCapture View)
              ├── Aciona câmera/dispositivo QFace
              ├── Usuário posiciona rosto
              ├── Captura template via qface:captureTemplate (IPC)
              └── Chama electron.dashboard.completeCaptureRequest(requestId, template)
                       │
                       ▼
                  IPC → capture:completeCaptureRequest
                       │
                       ▼
                  POST /internal/capture/complete { requestId, template, quality, imageBase64 }
                       │
                       ▼
                  completeCaptureFromElectron()
                       └─► Resolve response pendente → HTTP 200 para sistema externo
</code></pre>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f539.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_blue_diamond" title=":small_blue_diamond:" alt="🔹" /> Fluxo 4: Gerenciamento do Serviço Windows</h2>
<p dir="auto"><strong>Explicação simplificada (Suporte):</strong></p>
<blockquote>
<p dir="auto">O usuário pode instalar, iniciar, parar e desinstalar o serviço da API diretamente pela tela de Gerenciamento do Dashboard. O sistema usa o NSSM (ferramenta especial) para registrar o .exe da API como um serviço do Windows.</p>
</blockquote>
<p dir="auto"><strong>Explicação técnica (Dev):</strong></p>
<pre><code>React (Dashboard) → window.electron.dashboard.installService(name, displayName, apiPath)
   │
   ▼
IPC: dashboard:installService
   │
   ▼
windows-service-manager.ts → installWindowsService()
   ├── Resolve caminho do nssm.exe (win32/ ou win64/)
   ├── Executa: nssm install &lt;serviceName&gt; &lt;exePath&gt;
   ├── Configura: nssm set &lt;serviceName&gt; AppDirectory &lt;dir&gt;
   ├── Configura: nssm set &lt;serviceName&gt; AppEnvironmentExtra CONFIG_PATH=... QFACE_DLL_PATH=...
   └── Executa: nssm start &lt;serviceName&gt;
</code></pre>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f539.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_blue_diamond" title=":small_blue_diamond:" alt="🔹" /> Fluxo 5: Configuração e Tema</h2>
<p dir="auto"><strong>Explicação simplificada (Suporte):</strong></p>
<blockquote>
<p dir="auto">As configurações são salvas em um arquivo <code>application.json</code> tanto na pasta do aplicativo quanto na pasta do serviço de API. Quando o usuário altera as configurações, ambos são atualizados ao mesmo tempo.</p>
</blockquote>
<p dir="auto"><strong>Explicação técnica (Dev):</strong></p>
<pre><code>React ConfigContext
   ├── loadConfig() → IPC:loadConfig → main.ts lê config/application.json
   ├── saveConfig(updates) → IPC:saveConfig → main.ts escreve config/application.json
   │                                          → HTTP POST /internal/config/update (API sincroniza)
   └── LocalStorage como cache temporário (chave: 'qface-app-config')
</code></pre>
<hr />
<h1><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/2699.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--gear" title=":gear:" alt="⚙" />️ 5. ROTINAS E MÉTODOS IMPORTANTES</h1>
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f538.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_orange_diamond" title=":small_orange_diamond:" alt="🔸" /> <code>convertBiometricTemplate</code></h2>
<p dir="auto"><strong>Descrição simplificada:</strong></p>
<blockquote>
<p dir="auto">Recebe um conjunto de imagens, conecta no leitor QFace e gera os templates biométricos correspondentes.</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica:</strong></p>
<ul>
<li><strong>Localização:</strong> <a href="insoft-qface-win-api/src/controller/biometricTemplateController.ts">insoft-qface-win-api/src/controller/biometricTemplateController.ts</a></li>
<li><strong>Rota:</strong> <code>POST /v1/foto/converter</code></li>
</ul>
<p dir="auto"><strong>Parâmetros (Request Body):</strong></p>
<pre><code class="language-json">{
  "pictures": [
    {
      "personId": 123,
      "image": "&lt;base64 da imagem facial&gt;"
    }
  ]
}
</code></pre>
<p dir="auto"><strong>Retorno (HTTP 200):</strong></p>
<pre><code class="language-json">{
  "success": true,
  "pictures": [
    {
      "personId": 123,
      "template": "4A1B2C...",
      "quality": 85
    }
  ]
}
</code></pre>
<p dir="auto"><strong>Regras de negócio:</strong></p>
<ul>
<li>Usa <code>QFaceMutex</code> para garantir que apenas uma conversão ocorra por vez (DLL não é thread-safe)</li>
<li>Processa imagens <strong>sequencialmente</strong> (não em paralelo)</li>
<li>Apaga todos os templates do dispositivo antes de iniciar (<code>QF_DeleteAll</code>)</li>
<li>Salva imagens em <code>imagens/face_&lt;personId&gt;.jpeg</code></li>
<li>Salva templates em <code>templates/bio_&lt;personId&gt;.tmp</code></li>
<li>O campo <code>image</code> no retorno é <strong>removido</strong> para evitar overflow de memória</li>
</ul>
<p dir="auto"><strong>Possíveis erros:</strong></p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Código</th>
<th>Significado</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>repp.message.22</code></td>
<td><code>pictures</code> não é um array válido</td>
</tr>
<tr>
<td><code>repp.message.24</code></td>
<td>Falha ao conectar no dispositivo QFace</td>
</tr>
<tr>
<td><code>repp.message.25</code></td>
<td>Falha ao apagar templates existentes</td>
</tr>
<tr>
<td><code>repp.message.27</code></td>
<td>Imagem inválida para template facial</td>
</tr>
<tr>
<td><code>repp.message.47</code></td>
<td>Falha ao ler template gerado</td>
</tr>
</tbody>
</table>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f538.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_orange_diamond" title=":small_orange_diamond:" alt="🔸" /> <code>capturePicture</code></h2>
<p dir="auto"><strong>Descrição simplificada:</strong></p>
<blockquote>
<p dir="auto">Inicia uma captura ao vivo usando a câmera do QFace. A requisição fica "suspensa" aguardando o usuário posicionar o rosto na frente do leitor.</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica:</strong></p>
<ul>
<li><strong>Localização:</strong> <a href="insoft-qface-win-api/src/controller/biometricTemplateController.ts">insoft-qface-win-api/src/controller/biometricTemplateController.ts</a></li>
<li><strong>Rota:</strong> <code>POST /v1/foto/capturar</code></li>
</ul>
<p dir="auto"><strong>Parâmetros (Request Body):</strong></p>
<pre><code class="language-json">{
  "personId": 123,
  "includeBase64": false
}
</code></pre>
<p dir="auto"><strong>Comportamento:</strong></p>
<ul>
<li>Verifica disponibilidade do QFace <strong>antes</strong> de iniciar (fail-fast)</li>
<li>Armazena a resposta HTTP pendente em <code>pendingCaptureRequests</code> (Map)</li>
<li>O timeout padrão evita que a requisição fique aberta indefinidamente</li>
<li>A resolução ocorre via chamada interna do Electron: <code>POST /internal/capture/complete</code></li>
</ul>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f538.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_orange_diamond" title=":small_orange_diamond:" alt="🔸" /> <code>startApiServer</code></h2>
<p dir="auto"><strong>Descrição simplificada:</strong></p>
<blockquote>
<p dir="auto">Tenta iniciar o servidor da API usando o método mais adequado disponível (serviço Windows, .exe, ou API já rodando).</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica:</strong></p>
<ul>
<li><strong>Localização:</strong> <a href="insoft-qface-app/electron/main/main.ts">insoft-qface-app/electron/main/main.ts</a></li>
<li><strong>Chamado por:</strong> IPC <code>dashboard:startApi</code>, e na inicialização do app</li>
</ul>
<p dir="auto"><strong>Lógica de decisão:</strong></p>
<pre><code>1. API já está acessível via HTTP healthcheck? → Registra como running
2. Serviço Windows instalado?
   ├── Rodando? → Healthcheck → Registra
   └── Parado? → sc start → Aguarda healthcheck (15s)
3. Em produção sem serviço → Retorna erro
4. Em desenvolvimento → Tenta spawn do .exe diretamente
</code></pre>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f538.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_orange_diamond" title=":small_orange_diamond:" alt="🔸" /> <code>connectWebSocket</code></h2>
<p dir="auto"><strong>Descrição simplificada:</strong></p>
<blockquote>
<p dir="auto">Cria uma conexão em tempo real entre o aplicativo e o servidor de API, para receber notificações imediatas sobre conversões e capturas.</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica:</strong></p>
<ul>
<li><strong>Localização:</strong> <a href="insoft-qface-app/electron/main/main.ts">insoft-qface-app/electron/main/main.ts</a></li>
<li>Conecta em <code>http://localhost:3133</code> (<a href="http://Socket.IO" rel="nofollow ugc">Socket.IO</a>)</li>
<li>Reconexão automática infinita com backoff exponencial (1s → 5s)</li>
<li>Ouve eventos: <code>api:convert:start</code>, <code>api:convert:item</code>, <code>api:convert:done</code>, <code>api:capture:start</code></li>
<li>Cada evento é repassado via IPC para o frontend React</li>
</ul>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f538.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_orange_diamond" title=":small_orange_diamond:" alt="🔸" /> <code>QFaceSDK.initSocket</code></h2>
<p dir="auto"><strong>Descrição simplificada:</strong></p>
<blockquote>
<p dir="auto">Conecta o software ao leitor QFace pela rede local.</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica:</strong></p>
<ul>
<li><strong>Localização:</strong> <a href="insoft-qface-win-api/src/sdk/qface-sdk.ts">insoft-qface-win-api/src/sdk/qface-sdk.ts</a></li>
<li>Chama <code>QF_InitSocket(deviceIp, devicePort, asciiMode)</code> na DLL nativa via <strong>Koffi (FFI)</strong></li>
<li><code>asciiMode = false</code> → protocolo binário (padrão)</li>
<li>Retorna <code>true</code> se <code>QF_SUCCESS (0)</code>, <code>false</code> caso contrário</li>
<li>Mapeia todos os códigos de erro da DLL (de <code>-1</code> a <code>-304</code>)</li>
</ul>
<p dir="auto"><strong>Principais erros da DLL:</strong></p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Código</th>
<th>Significado</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>-302</code></td>
<td><code>QF_ERR_CANNOT_OPEN_SOCKET</code> — IP errado ou dispositivo offline</td>
</tr>
<tr>
<td><code>-303</code></td>
<td><code>QF_ERR_CANNOT_CONNECT_SOCKET</code> — Porta bloqueada ou firewall</td>
</tr>
<tr>
<td><code>-305</code></td>
<td><code>QF_ERR_READ_SOCKET_TIMEOUT</code> — Dispositivo não respondeu</td>
</tr>
</tbody>
</table>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f538.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_orange_diamond" title=":small_orange_diamond:" alt="🔸" /> <code>QFaceMutex.runExclusive</code></h2>
<p dir="auto"><strong>Descrição simplificada:</strong></p>
<blockquote>
<p dir="auto">Garante que apenas uma operação de conversão aconteça por vez, evitando travamentos na DLL.</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica:</strong></p>
<ul>
<li><strong>Localização:</strong> <a href="insoft-qface-win-api/src/server/index.ts">insoft-qface-win-api/src/server/index.ts</a></li>
<li>Implementação de mutex assíncrono com fila (FIFO)</li>
<li><strong>Motivo:</strong> A DLL <code>QFM_SDK_DLL.dll</code> <strong>não é thread-safe</strong> — chamadas concorrentes causam crash</li>
<li>Todas as operações que acessam a DLL devem usar <code>qfaceMutex.runExclusive()</code></li>
</ul>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f538.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_orange_diamond" title=":small_orange_diamond:" alt="🔸" /> <code>CertificateStore.ensureInstalled</code></h2>
<p dir="auto"><strong>Descrição simplificada:</strong></p>
<blockquote>
<p dir="auto">Instala automaticamente o certificado digital do aplicativo no Windows para reduzir bloqueios por antivírus ao acessar a câmera.</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica:</strong></p>
<ul>
<li><strong>Localização:</strong> <a href="insoft-qface-app/electron/main/CertificateStore.ts">insoft-qface-app/electron/main/CertificateStore.ts</a></li>
<li>Verifica se o certificado <code>Insoft4 QFace App</code> já está em <code>LocalMachine\Root</code></li>
<li>Se não estiver, executa <code>certutil -addstore Root &lt;certPath&gt;</code></li>
<li>Chamado automaticamente na inicialização do Electron</li>
</ul>
<hr />
<h2><img src="http://insoft-docker1:4567/assets/plugins/nodebb-plugin-emoji/emoji/android/1f538.png?v=8k80dgruung" class="not-responsive emoji emoji-android emoji--small_orange_diamond" title=":small_orange_diamond:" alt="🔸" /> <code>normalizeIpcPayload</code> (Preload)</h2>
<p dir="auto"><strong>Descrição simplificada:</strong></p>
<blockquote>
<p dir="auto">Traduz automaticamente os códigos de mensagem (<code>repp.message.X</code>) para texto legível em Português antes de mostrar no frontend.</p>
</blockquote>
<p dir="auto"><strong>Descrição técnica:</strong></p>
<ul>
<li><strong>Localização:</strong> <a href="insoft-qface-app/electron/main/preload.ts">insoft-qface-app/electron/main/preload.ts</a></li>
<li>Percorre recursivamente o payload de qualquer chamada IPC</li>
<li>Identifica strings que correspondem ao padrão <code>/^repp\.message\.\d+$/</code></li>
<li>Faz lookup no catálogo <code>pt-BR.json</code> (carregado uma vez e cacheado)</li>
<li>Aplica a tradução antes de retornar ao React</li>
</ul>
<hr />
<h3>A documentação continua na parte 2, através da seguinte URL:</h3>
<h4><a href="https://forum.insoft4.com.br/topic/502/documenta%C3%A7%C3%A3o-t%C3%A9cnica-app-api-rest-parte-2" rel="nofollow ugc">Documentação Técnica App + API REST - Parte 2</a></h4>
]]></description><link>http://insoft-docker1:4567/topic/501/documentação-técnica-app-api-rest-parte-1</link><generator>RSS for Node</generator><lastBuildDate>Sat, 06 Jun 2026 03:26:12 GMT</lastBuildDate><atom:link href="http://insoft-docker1:4567/topic/501.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 22 May 2026 14:35:25 GMT</pubDate><ttl>60</ttl></channel></rss>