From 37205d7e23474960553eae31a14933be1c1a97a0 Mon Sep 17 00:00:00 2001 From: Rafael Lopes Date: Tue, 6 Jan 2026 14:50:26 -0300 Subject: [PATCH] =?UTF-8?q?DOC:=20Documenta=C3=A7=C3=A3o=20ajustada=20praa?= =?UTF-8?q?=20se=20adequar=20a=20mudan=C3=A7as?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 369 ++++++++++++++++++++++++------------- src/shared/utils/logger.js | 2 +- 2 files changed, 243 insertions(+), 128 deletions(-) diff --git a/README.md b/README.md index 2e49032..6e1c411 100644 --- a/README.md +++ b/README.md @@ -1,130 +1,146 @@ -# Serviço de Integração HubSoft <> GLPI +# Serviço de Integração HubSoft ⇄ GLPI -![Node.js](https://img.shields.io/badge/Node.js-18.x-green) ![Express.js](https://img.shields.io/badge/Express.js-4.x-blue) ![PostgreSQL](https://img.shields.io/badge/Database-PostgreSQL-blue) ![License](https://img.shields.io/badge/License-MIT-yellow.svg) +![Node.js](https://img.shields.io/badge/Node.js-18.x-green) +![Express.js](https://img.shields.io/badge/Express.js-4.x-blue) +![PostgreSQL](https://img.shields.io/badge/Database-PostgreSQL-blue) +![PM2](https://img.shields.io/badge/Process%20Manager-PM2-blue) +![License](https://img.shields.io/badge/License-MIT-yellow.svg) -Este serviço realiza a integração e sincronização de tickets entre as plataformas **HubSoft** e **GLPI**, garantindo que as informações fluam de maneira consistente e automatizada entre os dois sistemas. +Este projeto é um **serviço de integração entre HubSoft e GLPI**, responsável por sincronizar **tickets, fechamentos e comentários**, utilizando **Node.js**, **PostgreSQL** e uma arquitetura baseada em **Clean Architecture**. -## ✨ Funcionalidades Principais - -- **Sincronização Bidirecional Parcial**: - - **Criação**: Tickets abertos no HubSoft são automaticamente criados no GLPI. - - **Fechamento**: Tickets "Mundiale" fechados no GLPI disparam o fechamento do atendimento correspondente no HubSoft. -- **Processamento Assíncrono**: Utiliza um cron job para processar a criação de tickets em segundo plano, sem impactar a performance da API. -- **Banco de Dados Intermediário**: Usa um banco de dados PostgreSQL para gerenciar o estado da sincronização, garantindo resiliência e rastreabilidade. -- **Mecanismo de Trava (Locking)**: Previne condições de corrida e processamento duplicado de webhooks. -- **Configuração Flexível**: Todas as chaves de API e conexões de banco de dados são gerenciadas por variáveis de ambiente. -- **Logging Detalhado**: Registra todas as operações e erros em arquivos de log para fácil depuração. +O foco do projeto é: +- confiabilidade +- idempotência +- isolamento de responsabilidades +- facilidade de manutenção e evolução --- -## 🏗️ Arquitetura e Fluxo de Dados +## ✨ Funcionalidades -A aplicação opera com dois fluxos principais: - -### 1. Fluxo de Criação de Tickets (Cron Job) - -Este fluxo roda a cada 5 minutos para sincronizar novos atendimentos do HubSoft para o GLPI. - -``` -┌──────────────────┐ ┌───────────────────┐ ┌──────────────────┐ ┌──────────┐ -│ DB do HubSoft ├─────►│ Serviço (Cron) ├─────►│ DB Intermediário├─────►│ API GLPI │ -└──────────────────┘ └───────────────────┘ └──────────────────┘ └──────────┘ - (Lê) (Processa dados) (Salva & Trava) (Cria Ticket) -``` - -1. O **Cron Job** é disparado. -2. O serviço consulta o banco de dados do **HubSoft** em busca de novos atendimentos. -3. Os dados são processados e salvos no **Banco de Dados Intermediário** com o status `pending_create`. -4. O serviço lê os tickets pendentes, formata os dados e os envia para a **API do GLPI** para criar o ticket. -5. Após a criação, o status no banco intermediário é atualizado para `created_glpi`. - -### 2. Fluxo de Fechamento de Tickets (Webhook) - -Este fluxo é iniciado por um evento de fechamento de ticket no GLPI. - -``` -┌──────────────┐ ┌──────────────────┐ ┌────────────────┐ ┌──────────────────┐ -│ GLPI Webhook ├─────►│ Serviço (API) ├─────►│ API do HubSoft ├─────►│ DB Intermediário│ -└──────────────┘ └──────────────────┘ └────────────────┘ └──────────────────┘ - (Dispara) (Valida e Trava) (Fecha Atendimento) (Atualiza Status) -``` - -1. O **GLPI** dispara um webhook quando um ticket é fechado. -2. A API do serviço recebe a requisição e verifica se o ticket é elegível (contém "Mundiale" no título). -3. O serviço obtém uma **trava** no banco de dados intermediário, mudando o status para `processing_close` para evitar processamento duplicado. -4. Uma chamada é feita para a **API do HubSoft** para fechar o atendimento correspondente. -5. Após o sucesso, o status no banco intermediário é atualizado para `closed_glpi`. +- Criação automática de tickets no **GLPI** a partir de atendimentos do **HubSoft** +- Fechamento automático de atendimentos no **HubSoft** a partir de tickets encerrados no **GLPI** +- Sincronização de **comentários** do GLPI para o HubSoft +- Processamento assíncrono via **cron/worker** +- Controle de estado e idempotência via **banco intermediário** +- Prevenção de concorrência e duplicidade de eventos +- Execução separada de **API** e **Worker** +- Suporte a execução local, desenvolvimento e produção --- -## 🚀 Instalação e Execução +## 🧱 Arquitetura -### Pré-requisitos +O projeto segue princípios da **Clean Architecture**, separando claramente: -- Node.js (versão 18.x ou superior) -- NPM -- Acesso a dois bancos de dados PostgreSQL (um para o HubSoft e outro para a aplicação). - -### 1. Clone o Repositório - -```bash -git clone ssh://usuario.autorizado@10.0.120.75:60000/home/desenvolvimento/HUBXGLPI/HUBXGLPI.git -cd HUBXGLPI +``` +Controller → UseCase → Repository → Infra ``` -### 2. Instale as Dependências +### Camadas -```bash -npm install +- **Controller** + - Entrada HTTP (webhooks, endpoints) + - Não contém regra de negócio +- **UseCases** + - Regras de negócio + - Orquestração dos fluxos +- **Repositories** + - Contratos de acesso a dados e integrações +- **Infra** + - Implementações técnicas (DB, APIs, cron, HTTP) + +--- + +## 🔄 Fluxos de Integração + +### 1. Criação de Tickets (HubSoft → GLPI) + +Fluxo assíncrono executado por **worker (cron)**. + +``` +HubSoft DB + ↓ +Worker (Cron) + ↓ +Banco Intermediário + ↓ +API GLPI ``` -### 3. Configure as Variáveis de Ambiente +**Passo a passo:** +1. Worker consulta novos atendimentos no HubSoft +2. Use case valida e transforma os dados +3. Registro é salvo no banco intermediário +4. Ticket é criado no GLPI +5. Status de sincronização é atualizado -Crie um arquivo `.env.production` e um `.env.development` na raiz do projeto, copiando o exemplo de `.env.example`. +--- -```bash -cp .env.example .env +### 2. Fechamento de Tickets (GLPI → HubSoft) + +Fluxo síncrono iniciado via webhook. + +``` +GLPI Webhook + ↓ +API (Controller) + ↓ +UseCase + ↓ +API HubSoft + ↓ +Banco Intermediário ``` -Preencha o arquivo `.env` com as credenciais corretas: +**Regras importantes:** +- Apenas tickets elegíveis (ex: tipo *Mundiale*) +- Controle de lock para evitar duplicidade +- Atualização de status após sucesso -```ini -# Configurações do Servidor -PORT=3000 +--- -# Banco de Dados da Aplicação (HubGLPI) -HUBGLPI_DB_HOST=localhost -HUBGLPI_DB_PORT=5432 -HUBGLPI_DB_USER=postgres -HUBGLPI_DB_PASSWORD=sua_senha -HUBGLPI_DB_NAME=hubglpi +### 3. Sincronização de Comentários (GLPI → HubSoft) -# Banco de Dados do HubSoft (Acesso de Leitura) -HUBSOFT_DB_HOST=ip_do_banco_hubsoft -HUBSOFT_DB_PORT=5432 -HUBSOFT_DB_USER=usuario_leitura -HUBSOFT_DB_PASSWORD=senha_leitura -HUBSOFT_DB_NAME=hubsoft +Fluxo acionado por webhook do GLPI. -# API do GLPI -GLPI_API_URL=https://seu-glpi.com/apirest.php -GLPI_APP_TOKEN=seu_app_token -GLPI_USER_TOKEN=seu_user_token - -# API do HubSoft -HUBSOFT_API_URL=https://seu-hubsoft.com/api/v1 -HUBSOFT_API_TOKEN=seu_token_hubsoft +``` +GLPI Webhook + ↓ +API (Controller) + ↓ +UseCase + ↓ +API HubSoft + ↓ +Banco Intermediário ``` -### 4. Inicie a Aplicação +**Detalhes:** +- Sanitização de HTML/texto +- Controle por `comment_id` e `source_comment_id` +- Garantia de idempotência +- Comentários duplicados são ignorados -```bash -NODE_ENV=development node src/server.js -ou -NODE_ENV=production node src/server.js -``` +--- -O servidor será iniciado, e o cron job começará a ser executado em segundo plano. +## 🗄️ Banco de Dados Intermediário + +O banco intermediário é **fundamental** para a integração. + +Ele é responsável por: +- Controle de estado dos tickets +- Idempotência de webhooks +- Lock de processamento +- Auditoria e rastreabilidade + +### Exemplos de status + +- `pending_create` +- `created` +- `processing_close` +- `closed` +- `synced` --- @@ -132,33 +148,132 @@ O servidor será iniciado, e o cron job começará a ser executado em segundo pl ``` src/ -├── app.js # Configuração da instância do Express. -├── server.js # Ponto de entrada: inicia o servidor e o cron job. -├── routes.js # Definição das rotas da API. -│ -├── config/ # Arquivos de configuração. -│ ├── apiConfig.js # Configuração das APIs externas. -│ ├── dbConfig.js # Configuração dos bancos de dados. -│ └── envLoader.js # Carregador de variáveis de ambiente. -│ -├── controller/ # Camada que lida com requisições HTTP. -│ ├── ClosureController.js # Controller para o webhook de fechamento. -│ └── processController.js # Controller para o fluxo de criação via cron. -│ -├── data/ # Configuração da conexão com os bancos. -│ ├── hubglpiDataBase.js # Pool de conexão para o DB da aplicação. -│ └── hubsoftDataBase.js # Pool de conexão para o DB do HubSoft. -│ -├── model/ # Camada de acesso a dados. -│ ├── glpiModel.js # Funções para interagir com a API do GLPI. -│ ├── hubglpiModel.js # Funções para interagir com o DB da aplicação. -│ └── hubsoftModel.js # Funções para interagir com o DB do HubSoft. -│ -├── services/ # Camada de lógica de negócio. -│ ├── hubsoftService.js # Lógica para interagir com a API do HubSoft. -│ └── ticketService.js # Lógica de negócio para o fechamento de tickets. -│ -└── utils/ # Funções utilitárias. - ├── commentSanitizer.js# Limpeza de texto e HTML. - └── logger.js # Configuração do sistema de logs (Winston). +├── config/ # Configurações gerais +├── infra/ # Infraestrutura +│ ├── api/ # Clientes de APIs externas +│ ├── cron/ # Workers / Jobs agendados +│ ├── db/ +│ │ ├── connections/ +│ │ └── repositories/ +│ └── http/ +│ └── routes/ +├── modules/ # Domínio (Clean Architecture) +│ ├── close/ +│ ├── comments/ +│ ├── createTickets/ +│ └── tickets/ +├── shared/ # Código compartilhado +│ └── utils/ +├── logs/ # Logs da aplicação +└── server.js # Bootstrap da aplicação ``` + +--- + +## 🚀 Execução do Projeto + +### Pré-requisitos + +- Node.js 18+ +- NPM +- PostgreSQL +- PM2 (produção) + +```bash +npm install -g pm2 +``` + +--- + +### Variáveis de Ambiente + +Criar arquivos: + +```bash +.env.development +.env.production +``` + +Exemplo: + +```ini +PORT=3000 +NODE_ENV=development + +HUBGLPI_DB_HOST=localhost +HUBGLPI_DB_PORT=5432 +HUBGLPI_DB_USER=postgres +HUBGLPI_DB_PASSWORD=senha +HUBGLPI_DB_NAME=hubglpi + +HUBSOFT_DB_HOST=ip +HUBSOFT_DB_PORT=5432 +HUBSOFT_DB_USER=usuario +HUBSOFT_DB_PASSWORD=senha +HUBSOFT_DB_NAME=hubsoft + +GLPI_API_URL=https://seu-glpi/apirest.php +GLPI_APP_TOKEN=token +GLPI_USER_TOKEN=token + +HUBSOFT_API_URL=https://seu-hubsoft/api +HUBSOFT_API_TOKEN=token +``` + +--- + +## ▶️ Scripts NPM + +### Desenvolvimento + +Rodar **apenas a API**: +```bash +npm run dev:api +``` + +Rodar **apenas o worker (cron)**: +```bash +npm run dev:worker +``` + +--- + +### Produção (PM2) + +Rodar apenas a **API**: +```bash +pm2 start npm --name hubxglpi-api -- start:api +``` + +Rodar apenas o **Worker**: +```bash +pm2 start npm --name hubxglpi-worker -- start:worker +``` + +Rodarr **API e Worker**: +```bash +pm2 start ecosystem.config.js --env production + +Ver status: +```bash +pm2 status +``` + +Logs: +```bash +pm2 logs +``` + +--- + +## 🧠 Boas Práticas + +- Sempre utilizar o banco intermediário para controle de estado +- Controllers não devem conter lógica de negócio +- UseCases não devem conhecer detalhes de infraestrutura + +--- + +## 📜 Licença + +MIT diff --git a/src/shared/utils/logger.js b/src/shared/utils/logger.js index f33debc..7825a82 100644 --- a/src/shared/utils/logger.js +++ b/src/shared/utils/logger.js @@ -6,7 +6,7 @@ require('winston-daily-rotate-file'); const fs = require('fs'); // verifica se a pasta de logs existe, se não, cria -const logsDir = path.join(__dirname, '../../logs'); +const logsDir = path.join(__dirname, '../../../logs'); if (!fs.existsSync(logsDir)) { fs.mkdirSync(logsDir, { recursive: true }); }