Files
hefesto/docs/MANUAL-TECNICO.html

2194 lines
54 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>HEFESTO - Manual Técnico</title>
<style>
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap');
@page {
size: A4;
margin: 2cm 2cm 2.5cm 2cm;
@top-center {
content: "";
}
@bottom-center {
content: counter(page);
font-family: 'Inter', 'Segoe UI', sans-serif;
font-size: 9pt;
color: #999;
}
}
@page :first {
margin: 0;
@bottom-center { content: ""; }
}
* { box-sizing: border-box; }
body {
font-family: 'Inter', 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
font-size: 10.5pt;
line-height: 1.7;
color: #333;
-webkit-print-color-adjust: exact !important;
print-color-adjust: exact !important;
}
/* COVER PAGE */
.cover {
page-break-after: always;
width: 210mm;
height: 297mm;
margin: -2cm;
padding: 0;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: linear-gradient(160deg, #0D1B2A 0%, #1A237E 40%, #1A237E 60%, #0D1B2A 100%);
color: white;
text-align: center;
position: relative;
overflow: hidden;
}
.cover::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 8px;
background: linear-gradient(90deg, #E65100, #FF8F00, #FFB300);
}
.cover::after {
content: '';
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 8px;
background: linear-gradient(90deg, #FFB300, #FF8F00, #E65100);
}
.cover .logo-icon {
font-size: 80pt;
margin-bottom: 10px;
filter: drop-shadow(0 4px 20px rgba(255, 143, 0, 0.5));
}
.cover .brand {
font-size: 42pt;
font-weight: 900;
letter-spacing: 12px;
margin-bottom: 5px;
background: linear-gradient(90deg, #FF8F00, #FFB300);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.cover .divider {
width: 120px;
height: 3px;
background: linear-gradient(90deg, transparent, #FF8F00, transparent);
margin: 20px auto;
}
.cover .manual-title {
font-size: 22pt;
font-weight: 300;
letter-spacing: 3px;
text-transform: uppercase;
color: rgba(255,255,255,0.95);
margin-bottom: 8px;
}
.cover .manual-subtitle {
font-size: 12pt;
font-weight: 300;
color: rgba(255,255,255,0.6);
margin-bottom: 60px;
}
.cover .meta {
position: absolute;
bottom: 50px;
text-align: center;
width: 100%;
}
.cover .company {
font-size: 11pt;
font-weight: 500;
letter-spacing: 4px;
text-transform: uppercase;
color: rgba(255,255,255,0.5);
margin-bottom: 8px;
}
.cover .date {
font-size: 10pt;
color: rgba(255,255,255,0.35);
letter-spacing: 2px;
}
/* GEOMETRIC DECORATIONS */
.cover .geo1 {
position: absolute;
top: 60px;
right: 60px;
width: 200px;
height: 200px;
border: 1px solid rgba(255,143,0,0.15);
border-radius: 50%;
}
.cover .geo2 {
position: absolute;
bottom: 120px;
left: 40px;
width: 150px;
height: 150px;
border: 1px solid rgba(255,143,0,0.1);
transform: rotate(45deg);
}
/* PAGE HEADER */
.page-header {
page-break-after: avoid;
margin-bottom: 30px;
padding-bottom: 12px;
border-bottom: 2px solid #E65100;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 9pt;
color: #999;
letter-spacing: 2px;
text-transform: uppercase;
}
.page-header .left {
font-weight: 700;
color: #1A237E;
}
.page-header .right {
color: #E65100;
}
/* TABLE OF CONTENTS */
.toc-page {
page-break-after: always;
}
.toc-page h2 {
font-size: 18pt;
color: #1A237E;
border: none;
padding: 0;
margin-bottom: 25px;
letter-spacing: 3px;
text-transform: uppercase;
}
.toc-page h2::before {
content: '';
display: block;
width: 50px;
height: 3px;
background: #E65100;
margin-bottom: 15px;
}
/* HEADINGS */
h1 {
font-size: 22pt;
font-weight: 800;
color: #1A237E;
margin-top: 40px;
margin-bottom: 20px;
padding-bottom: 10px;
border-bottom: 3px solid #E65100;
page-break-after: avoid;
letter-spacing: -0.5px;
}
h2 {
font-size: 16pt;
font-weight: 700;
color: #1A237E;
margin-top: 35px;
margin-bottom: 15px;
padding-left: 15px;
border-left: 4px solid #E65100;
page-break-after: avoid;
}
h3 {
font-size: 13pt;
font-weight: 600;
color: #283593;
margin-top: 25px;
margin-bottom: 12px;
page-break-after: avoid;
}
h4 {
font-size: 11pt;
font-weight: 600;
color: #E65100;
margin-top: 20px;
margin-bottom: 10px;
text-transform: uppercase;
letter-spacing: 1px;
}
/* FIRST H1 — remove top margin after cover */
.content > h1:first-child {
margin-top: 0;
}
/* PARAGRAPHS */
p {
margin-bottom: 12px;
text-align: justify;
hyphens: auto;
}
/* STRONG/BOLD in special contexts */
strong {
color: #1A237E;
font-weight: 600;
}
/* TABLES */
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
font-size: 9.5pt;
page-break-inside: avoid;
box-shadow: 0 1px 4px rgba(0,0,0,0.08);
border-radius: 6px;
overflow: hidden;
}
thead {
background: linear-gradient(135deg, #1A237E, #283593);
}
th {
color: white;
font-weight: 600;
text-align: left;
padding: 12px 14px;
font-size: 9pt;
text-transform: uppercase;
letter-spacing: 0.5px;
}
td {
padding: 10px 14px;
border-bottom: 1px solid #E8EAF6;
vertical-align: top;
}
tbody tr:nth-child(even) {
background-color: #F5F5FF;
}
tbody tr:hover {
background-color: #E8EAF6;
}
/* Checkmark styling for comparison tables */
td:has(text("✅")), td:has(text("❌")) {
text-align: center;
font-size: 14pt;
}
/* CODE BLOCKS */
pre {
background: #1E1E2E;
color: #CDD6F4;
border-radius: 8px;
padding: 18px 20px;
font-size: 9pt;
line-height: 1.6;
overflow-x: auto;
margin: 18px 0;
page-break-inside: avoid;
border-left: 4px solid #E65100;
}
code {
font-family: 'JetBrains Mono', 'Fira Code', 'Consolas', monospace;
font-size: 9pt;
}
p code, li code, td code {
background: #EDE7F6;
color: #4A148C;
padding: 2px 7px;
border-radius: 4px;
font-size: 8.5pt;
}
/* LISTS */
ul, ol {
margin: 10px 0;
padding-left: 24px;
}
li {
margin-bottom: 6px;
line-height: 1.6;
}
li::marker {
color: #E65100;
font-weight: bold;
}
/* BLOCKQUOTES / CALLOUTS */
blockquote {
background: linear-gradient(135deg, #FFF3E0, #FFF8E1);
border-left: 4px solid #FF8F00;
margin: 20px 0;
padding: 16px 20px;
border-radius: 0 8px 8px 0;
font-style: normal;
page-break-inside: avoid;
}
blockquote p {
margin: 0;
color: #5D4037;
}
blockquote strong {
color: #E65100;
}
/* HORIZONTAL RULES */
hr {
border: none;
height: 2px;
background: linear-gradient(90deg, #E65100, #FF8F00, transparent);
margin: 35px 0;
}
/* LINKS */
a {
color: #1A237E;
text-decoration: none;
border-bottom: 1px solid #E65100;
}
/* INFO BOX */
.info-box {
background: #E3F2FD;
border-left: 4px solid #1565C0;
padding: 14px 18px;
border-radius: 0 8px 8px 0;
margin: 18px 0;
}
/* SUCCESS BOX */
.success-box {
background: #E8F5E9;
border-left: 4px solid #2E7D32;
padding: 14px 18px;
border-radius: 0 8px 8px 0;
margin: 18px 0;
}
/* WARNING BOX */
.warning-box {
background: #FFF3E0;
border-left: 4px solid #E65100;
padding: 14px 18px;
border-radius: 0 8px 8px 0;
margin: 18px 0;
}
/* PAGE BREAKS for major sections */
h1 {
page-break-before: always;
}
h1:first-of-type {
page-break-before: avoid;
}
/* FOOTER NOTE */
.doc-footer {
margin-top: 40px;
padding-top: 15px;
border-top: 1px solid #E0E0E0;
text-align: center;
font-size: 8.5pt;
color: #999;
font-style: italic;
}
/* Emoji sizing */
.emoji-icon {
font-size: 14pt;
}
/* Print optimizations */
@media print {
body { -webkit-print-color-adjust: exact !important; }
.cover { page-break-after: always; }
h1, h2, h3 { page-break-after: avoid; }
table, pre, blockquote { page-break-inside: avoid; }
}
</style>
</head>
<body>
<div class="cover">
<div class="geo1"></div>
<div class="geo2"></div>
<div class="logo-icon">🔥</div>
<div class="brand">HEFESTO</div>
<div class="divider"></div>
<div class="manual-title">Manual Técnico</div>
<div class="manual-subtitle">Documentação Técnica Completa</div>
<div class="meta">
<div class="company">Kislanski Industries &nbsp;|&nbsp; AI Vertice</div>
<div class="date">Fevereiro 2026 &nbsp;·&nbsp; v2.0</div>
</div>
</div>
<div class="toc-page">
<h2>Sumário</h2>
<div class="toc">
<ul>
<li><a href="#hefesto-manual-tecnico">HEFESTO — Manual Técnico</a><ul>
<li><a href="#1-visao-geral-da-arquitetura">1. Visão Geral da Arquitetura</a></li>
<li><a href="#2-stack-completa">2. Stack Completa</a></li>
<li><a href="#3-estrutura-de-pastas">3. Estrutura de Pastas</a><ul>
<li><a href="#31-backend">3.1 Backend</a></li>
<li><a href="#32-frontend">3.2 Frontend</a></li>
</ul>
</li>
<li><a href="#4-modelo-de-dados">4. Modelo de Dados</a><ul>
<li><a href="#41-diagrama-de-entidades">4.1 Diagrama de Entidades</a></li>
<li><a href="#42-descricao-das-entidades">4.2 Descrição das Entidades</a></li>
<li><a href="#43-perfis-de-acesso-rbac">4.3 Perfis de Acesso (RBAC)</a></li>
</ul>
</li>
<li><a href="#5-api-endpoints">5. API — Endpoints</a><ul>
<li><a href="#51-autenticacao-apiauth">5.1 Autenticação (/api/auth)</a></li>
<li><a href="#52-usuarios-apiusers">5.2 Usuários (/api/users)</a></li>
<li><a href="#53-locais-apilocais">5.3 Locais (/api/locais)</a></li>
<li><a href="#54-centros-de-custo-apicentros-custo">5.4 Centros de Custo (/api/centros-custo)</a></li>
<li><a href="#55-categorias-apicategorias">5.5 Categorias (/api/categorias)</a></li>
<li><a href="#56-fornecedores-apifornecedores">5.6 Fornecedores (/api/fornecedores)</a></li>
<li><a href="#57-demandas-apidemandas">5.7 Demandas (/api/demandas)</a></li>
<li><a href="#58-propostas-apipropostas">5.8 Propostas (/api/propostas)</a></li>
<li><a href="#59-orcamento-apiorcamento">5.9 Orçamento (/api/orcamento)</a></li>
<li><a href="#510-workflow-apiworkflow">5.10 Workflow (/api/workflow)</a></li>
<li><a href="#511-dashboard-apidashboard">5.11 Dashboard (/api/dashboard)</a></li>
<li><a href="#512-ordens-de-servico-apiordens-servico">5.12 Ordens de Serviço (/api/ordens-servico)</a></li>
<li><a href="#513-alertas-apialertas">5.13 Alertas (/api/alertas)</a></li>
<li><a href="#514-esg-sustentabilidade-apiesg">5.14 ESG / Sustentabilidade (/api/esg)</a></li>
<li><a href="#515-kpis-indicadores-de-performance-apikpis">5.15 KPIs — Indicadores de Performance (/api/kpis)</a></li>
<li><a href="#516-auditoria-e-compliance-apiaudit">5.16 Auditoria e Compliance (/api/audit)</a></li>
<li><a href="#517-importacao-de-dados-apiimport">5.17 Importação de Dados (/api/import)</a></li>
<li><a href="#518-relatorios-automatizados-apirelatorios">5.18 Relatórios Automatizados (/api/relatorios)</a></li>
<li><a href="#519-metas-e-progresso-apimetas">5.19 Metas e Progresso (/api/metas)</a></li>
<li><a href="#520-alertas-inteligentes-apialertas">5.20 Alertas Inteligentes (/api/alertas)</a></li>
</ul>
</li>
<li><a href="#6-autenticacao-e-autorizacao">6. Autenticação e Autorização</a><ul>
<li><a href="#61-fluxo-jwt">6.1 Fluxo JWT</a></li>
<li><a href="#62-guards-nestjs">6.2 Guards NestJS</a></li>
</ul>
</li>
<li><a href="#7-workflow-de-aprovacao">7. Workflow de Aprovação</a><ul>
<li><a href="#71-maquina-de-estados">7.1 Máquina de Estados</a></li>
<li><a href="#72-alcadas-de-aprovacao">7.2 Alçadas de Aprovação</a></li>
</ul>
</li>
<li><a href="#8-como-rodar-localmente">8. Como Rodar Localmente</a><ul>
<li><a href="#81-pre-requisitos">8.1 Pré-requisitos</a></li>
<li><a href="#82-backend">8.2 Backend</a></li>
<li><a href="#83-frontend">8.3 Frontend</a></li>
<li><a href="#84-acesso-inicial">8.4 Acesso Inicial</a></li>
</ul>
</li>
<li><a href="#9-deploy-em-producao">9. Deploy em Produção</a><ul>
<li><a href="#91-infraestrutura">9.1 Infraestrutura</a></li>
<li><a href="#92-nginx-config">9.2 Nginx Config</a></li>
<li><a href="#93-pm2">9.3 PM2</a></li>
</ul>
</li>
<li><a href="#10-variaveis-de-ambiente">10. Variáveis de Ambiente</a><ul>
<li><a href="#backend-env">Backend (.env)</a></li>
<li><a href="#frontend-env">Frontend (.env)</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
</div>
<div class="page-header">
<span class="left">HEFESTO — Manual Técnico</span>
<span class="right">v2.0</span>
</div>
<div class="content">
<h1 id="hefesto-manual-tecnico">HEFESTO — Manual Técnico</h1>
<p><strong>Sistema de Controle Orçamentário para Facilities</strong></p>
<p>Versão 2.0 | Fevereiro 2025</p>
<hr />
<h2 id="1-visao-geral-da-arquitetura">1. Visão Geral da Arquitetura</h2>
<p>O HEFESTO é uma aplicação web fullstack composta por:</p>
<ul>
<li><strong>Backend:</strong> API REST em NestJS (Node.js) com TypeORM</li>
<li><strong>Frontend:</strong> SPA em React + TypeScript com Vite</li>
<li><strong>Banco de Dados:</strong> SQLite (desenvolvimento) / PostgreSQL (produção)</li>
<li><strong>Autenticação:</strong> JWT com RBAC (Role-Based Access Control)</li>
</ul>
<pre><code>┌─────────────────┐ HTTP/REST ┌─────────────────┐
│ React SPA │ ◄──────────────► │ NestJS API │
│ (Vite) │ JWT Bearer │ (TypeORM) │
│ Port 5173 │ │ Port 3000 │
└─────────────────┘ └────────┬────────┘
┌────────▼────────┐
│ SQLite / PG │
└─────────────────┘
</code></pre>
<h2 id="2-stack-completa">2. Stack Completa</h2>
<table>
<thead>
<tr>
<th>Componente</th>
<th>Tecnologia</th>
<th>Versão</th>
</tr>
</thead>
<tbody>
<tr>
<td>Runtime</td>
<td>Node.js</td>
<td>22.x LTS</td>
</tr>
<tr>
<td>Backend Framework</td>
<td>NestJS</td>
<td>10.x</td>
</tr>
<tr>
<td>ORM</td>
<td>TypeORM</td>
<td>0.3.x</td>
</tr>
<tr>
<td>Frontend Framework</td>
<td>React</td>
<td>18.x</td>
</tr>
<tr>
<td>Build Tool</td>
<td>Vite</td>
<td>5.x</td>
</tr>
<tr>
<td>Linguagem</td>
<td>TypeScript</td>
<td>5.x</td>
</tr>
<tr>
<td>UI Components</td>
<td>Tailwind CSS</td>
<td>3.x</td>
</tr>
<tr>
<td>BD Desenvolvimento</td>
<td>SQLite3</td>
<td>5.x</td>
</tr>
<tr>
<td>BD Produção</td>
<td>PostgreSQL</td>
<td>16.x</td>
</tr>
<tr>
<td>Auth</td>
<td>@nestjs/jwt + passport</td>
<td>10.x</td>
</tr>
<tr>
<td>HTTP Client</td>
<td>Axios</td>
<td>1.x</td>
</tr>
<tr>
<td>Validação</td>
<td>class-validator</td>
<td>0.14.x</td>
</tr>
<tr>
<td>Documentação API</td>
<td>@nestjs/swagger</td>
<td>7.x</td>
</tr>
</tbody>
</table>
<h2 id="3-estrutura-de-pastas">3. Estrutura de Pastas</h2>
<h3 id="31-backend">3.1 Backend</h3>
<pre><code>backend/
├── src/
│ ├── main.ts # Bootstrap da aplicação
│ ├── app.module.ts # Módulo raiz
│ ├── common/ # Guards, decorators, pipes, interceptors
│ │ ├── guards/
│ │ │ ├── jwt-auth.guard.ts
│ │ │ └── roles.guard.ts
│ │ ├── decorators/
│ │ │ ├── roles.decorator.ts
│ │ │ └── current-user.decorator.ts
│ │ └── interceptors/
│ │ └── audit.interceptor.ts
│ ├── database/ # Configuração TypeORM, migrations, seeds
│ │ ├── database.module.ts
│ │ ├── migrations/
│ │ └── seeds/
│ └── modules/
│ ├── auth/ # Autenticação JWT, login, refresh token
│ │ ├── auth.controller.ts
│ │ ├── auth.service.ts
│ │ ├── auth.module.ts
│ │ ├── strategies/
│ │ │ └── jwt.strategy.ts
│ │ └── dto/
│ ├── users/ # CRUD de usuários e perfis
│ │ ├── users.controller.ts
│ │ ├── users.service.ts
│ │ ├── entities/
│ │ │ ├── usuario.entity.ts
│ │ │ └── perfil.entity.ts
│ │ └── dto/
│ ├── locais/ # Gestão de locais/unidades
│ ├── centros-custo/ # Centros de custo vinculados a locais
│ ├── categorias/ # Categorias de serviço
│ ├── fornecedores/ # Cadastro de fornecedores e certidões
│ ├── demandas/ # Abertura e gestão de demandas
│ ├── propostas/ # Recebimento e comparação de propostas
│ ├── orcamento/ # Orçamento planejado vs realizado
│ ├── workflow/ # Máquina de estados de aprovação
│ ├── dashboard/ # Indicadores e relatórios
│ ├── ordens-servico/ # Emissão e acompanhamento de OS
│ ├── esg/ # Métricas ESG e sustentabilidade
│ ├── kpis/ # Indicadores de performance
│ ├── audit/ # Auditoria e compliance avançado
│ ├── import/ # Importação de dados Excel/CSV
│ ├── relatorios/ # Relatórios automatizados
│ ├── metas/ # Metas e acompanhamento de progresso
│ └── alertas-inteligentes/ # Configuração e verificação de alertas
├── test/
├── nest-cli.json
├── tsconfig.json
└── package.json
</code></pre>
<h3 id="32-frontend">3.2 Frontend</h3>
<pre><code>frontend/
├── src/
│ ├── main.tsx # Entry point
│ ├── App.tsx # Router + Layout
│ ├── assets/ # Imagens, ícones
│ ├── components/ # Componentes reutilizáveis
│ │ ├── Layout/
│ │ ├── Sidebar/
│ │ ├── Header/
│ │ ├── DataTable/
│ │ ├── StatusBadge/
│ │ └── Charts/
│ ├── pages/
│ │ ├── Login.tsx # Tela de autenticação
│ │ ├── Dashboard.tsx # Painel de indicadores
│ │ ├── Demandas.tsx # Lista de demandas com filtros
│ │ ├── Landing.tsx # Página inicial / nova demanda
│ │ ├── Fornecedores.tsx # Gestão de fornecedores
│ │ ├── Orcamentos.tsx # Orçamento planejado vs realizado
│ │ ├── OrdensServico.tsx # Ordens de serviço
│ │ ├── Relatorios.tsx # Relatórios gerenciais
│ │ ├── Usuarios.tsx # Administração de usuários
│ │ ├── ESG.tsx # Dashboard ESG e métricas ambientais
│ │ ├── KPIs.tsx # Painel de indicadores de performance
│ │ ├── Auditoria.tsx # Logs de auditoria e compliance
│ │ ├── Importacao.tsx # Upload de planilhas Excel/CSV
│ │ ├── Metas.tsx # Metas e progresso por centro de custo
│ │ └── Alertas.tsx # Configuração de alertas inteligentes
│ ├── services/ # Axios clients e API calls
│ │ └── api.ts
│ ├── types/ # Interfaces TypeScript
│ └── index.css # Tailwind directives
├── vite.config.ts
├── tailwind.config.js
├── tsconfig.json
└── package.json
</code></pre>
<h2 id="4-modelo-de-dados">4. Modelo de Dados</h2>
<h3 id="41-diagrama-de-entidades">4.1 Diagrama de Entidades</h3>
<p>O sistema possui 21 entidades principais:</p>
<pre><code>perfis ──&lt; usuarios ──&lt; demandas ──&lt; itens_linha
│ │
│ ├──&lt; propostas
│ │
│ ├──&lt; workflow_aprovacao
│ │
│ └──&lt; ordens_servico ──&lt; avaliacoes
└──&lt; audit_log
locais ──&lt; centros_custo ──&lt; orcamento_planejado
categorias ──&lt; demandas
fornecedores ──&lt; certidoes
fornecedores ──&lt; propostas
alertas (standalone)
locais ──&lt; esg_metricas
locais ──&lt; esg_metas
centros_custo ──&lt; kpis
centros_custo ──&lt; metas
centros_custo ──&lt; alertas_config
categorias ──&lt; alertas_config
</code></pre>
<h3 id="42-descricao-das-entidades">4.2 Descrição das Entidades</h3>
<table>
<thead>
<tr>
<th>#</th>
<th>Entidade</th>
<th>Descrição</th>
<th>Campos Principais</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td><strong>perfis</strong></td>
<td>Perfis de acesso (RBAC)</td>
<td>id, nome, descricao, permissoes (JSON)</td>
</tr>
<tr>
<td>2</td>
<td><strong>usuarios</strong></td>
<td>Usuários do sistema</td>
<td>id, nome, email, senha_hash, perfil_id, ativo, ultimo_acesso</td>
</tr>
<tr>
<td>3</td>
<td><strong>locais</strong></td>
<td>Unidades/edifícios</td>
<td>id, nome, endereco, cidade, estado, cnpj, ativo</td>
</tr>
<tr>
<td>4</td>
<td><strong>centros_custo</strong></td>
<td>Centros de custo por local</td>
<td>id, codigo, descricao, local_id, ativo</td>
</tr>
<tr>
<td>5</td>
<td><strong>categorias</strong></td>
<td>Categorias de serviço</td>
<td>id, nome, descricao, sla_dias, ativo</td>
</tr>
<tr>
<td>6</td>
<td><strong>fornecedores</strong></td>
<td>Cadastro de fornecedores</td>
<td>id, razao_social, cnpj, contato, email, telefone, ativo, rating</td>
</tr>
<tr>
<td>7</td>
<td><strong>certidoes</strong></td>
<td>Certidões de fornecedores</td>
<td>id, fornecedor_id, tipo, arquivo_url, validade, status</td>
</tr>
<tr>
<td>8</td>
<td><strong>orcamento_planejado</strong></td>
<td>Budget por centro de custo/ano</td>
<td>id, centro_custo_id, ano, mes, valor_planejado, valor_realizado</td>
</tr>
<tr>
<td>9</td>
<td><strong>demandas</strong></td>
<td>Demandas de serviço</td>
<td>id, titulo, descricao, local_id, categoria_id, solicitante_id, status, prioridade, valor_estimado, created_at</td>
</tr>
<tr>
<td>10</td>
<td><strong>itens_linha</strong></td>
<td>Itens detalhados da demanda</td>
<td>id, demanda_id, descricao, quantidade, unidade, valor_unitario</td>
</tr>
<tr>
<td>11</td>
<td><strong>propostas</strong></td>
<td>Propostas de fornecedores</td>
<td>id, demanda_id, fornecedor_id, valor_total, arquivo_url, data_validade, status, observacoes</td>
</tr>
<tr>
<td>12</td>
<td><strong>workflow_aprovacao</strong></td>
<td>Etapas de aprovação</td>
<td>id, demanda_id, etapa, aprovador_id, status, comentario, data_acao</td>
</tr>
<tr>
<td>13</td>
<td><strong>ordens_servico</strong></td>
<td>Ordens de serviço emitidas</td>
<td>id, demanda_id, proposta_id, numero_os, data_inicio, data_fim_prevista, data_fim_real, status</td>
</tr>
<tr>
<td>14</td>
<td><strong>avaliacoes</strong></td>
<td>Avaliação pós-execução</td>
<td>id, ordem_servico_id, avaliador_id, nota, comentario, created_at</td>
</tr>
<tr>
<td>15</td>
<td><strong>audit_log</strong></td>
<td>Log de auditoria</td>
<td>id, usuario_id, acao, entidade, entidade_id, dados_antes, dados_depois, ip, created_at</td>
</tr>
<tr>
<td>16</td>
<td><strong>alertas</strong></td>
<td>Notificações e alertas</td>
<td>id, usuario_id, tipo, mensagem, lido, referencia_tipo, referencia_id, created_at</td>
</tr>
<tr>
<td>17</td>
<td><strong>esg_metricas</strong></td>
<td>Métricas ambientais ESG</td>
<td>id, local_id, tipo (energia/agua/residuos/emissoes_co2), valor, unidade_medida, periodo, observacoes, created_at</td>
</tr>
<tr>
<td>18</td>
<td><strong>esg_metas</strong></td>
<td>Metas ESG</td>
<td>id, local_id, tipo, descricao, valor_alvo, valor_atual, percentual_atingido, status, prazo, created_at</td>
</tr>
<tr>
<td>19</td>
<td><strong>kpis</strong></td>
<td>Indicadores de performance calculados</td>
<td>id, nome, valor, unidade, status_semaforo, centro_custo_id, periodo, calculated_at</td>
</tr>
<tr>
<td>20</td>
<td><strong>metas</strong></td>
<td>Metas por centro de custo</td>
<td>id, centro_custo_id, tipo (orcamento/operacional/esg), descricao, valor_alvo, valor_atual, percentual_atingido, status, prazo, created_at</td>
</tr>
<tr>
<td>21</td>
<td><strong>alertas_config</strong></td>
<td>Configuração de alertas inteligentes</td>
<td>id, tipo, centro_custo_id, categoria_id, limite_percentual, notificar_usuarios (JSON), ativo, created_at</td>
</tr>
</tbody>
</table>
<h3 id="43-perfis-de-acesso-rbac">4.3 Perfis de Acesso (RBAC)</h3>
<table>
<thead>
<tr>
<th>Perfil</th>
<th>Permissões</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>Admin</strong></td>
<td>Acesso total ao sistema, gestão de usuários e configurações</td>
</tr>
<tr>
<td><strong>Gestor Facilities</strong></td>
<td>CRUD de demandas, fornecedores, propostas, OS; aprovação nível 1</td>
</tr>
<tr>
<td><strong>Aprovador Financeiro</strong></td>
<td>Aprovação nível 2 (financeiro), visualização de orçamento</td>
</tr>
<tr>
<td><strong>Diretoria</strong></td>
<td>Aprovação nível 3 (alçada máxima), dashboard executivo</td>
</tr>
<tr>
<td><strong>Solicitante</strong></td>
<td>Abertura de demandas, acompanhamento do próprio pedido</td>
</tr>
<tr>
<td><strong>Fornecedor</strong></td>
<td>Envio de propostas, acompanhamento de OS atribuídas</td>
</tr>
</tbody>
</table>
<h2 id="5-api-endpoints">5. API — Endpoints</h2>
<h3 id="51-autenticacao-apiauth">5.1 Autenticação (<code>/api/auth</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST</td>
<td><code>/api/auth/login</code></td>
<td>Login com email/senha → JWT</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/auth/refresh</code></td>
<td>Renovar token</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/auth/logout</code></td>
<td>Invalidar token</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/auth/me</code></td>
<td>Dados do usuário logado</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/auth/forgot-password</code></td>
<td>Solicitar reset de senha</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/auth/reset-password</code></td>
<td>Resetar senha com token</td>
</tr>
</tbody>
</table>
<h3 id="52-usuarios-apiusers">5.2 Usuários (<code>/api/users</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/users</code></td>
<td>Listar usuários (paginado)</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/users/:id</code></td>
<td>Detalhes do usuário</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/users</code></td>
<td>Criar usuário</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/users/:id</code></td>
<td>Atualizar usuário</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/users/:id</code></td>
<td>Desativar usuário</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/perfis</code></td>
<td>Listar perfis</td>
</tr>
</tbody>
</table>
<h3 id="53-locais-apilocais">5.3 Locais (<code>/api/locais</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/locais</code></td>
<td>Listar locais</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/locais/:id</code></td>
<td>Detalhes do local</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/locais</code></td>
<td>Criar local</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/locais/:id</code></td>
<td>Atualizar local</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/locais/:id</code></td>
<td>Desativar local</td>
</tr>
</tbody>
</table>
<h3 id="54-centros-de-custo-apicentros-custo">5.4 Centros de Custo (<code>/api/centros-custo</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/centros-custo</code></td>
<td>Listar centros de custo</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/centros-custo/:id</code></td>
<td>Detalhes</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/centros-custo</code></td>
<td>Criar centro de custo</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/centros-custo/:id</code></td>
<td>Atualizar</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/centros-custo/:id</code></td>
<td>Desativar</td>
</tr>
</tbody>
</table>
<h3 id="55-categorias-apicategorias">5.5 Categorias (<code>/api/categorias</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/categorias</code></td>
<td>Listar categorias</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/categorias/:id</code></td>
<td>Detalhes</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/categorias</code></td>
<td>Criar categoria</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/categorias/:id</code></td>
<td>Atualizar</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/categorias/:id</code></td>
<td>Desativar</td>
</tr>
</tbody>
</table>
<h3 id="56-fornecedores-apifornecedores">5.6 Fornecedores (<code>/api/fornecedores</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/fornecedores</code></td>
<td>Listar fornecedores</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/fornecedores/:id</code></td>
<td>Detalhes com certidões</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/fornecedores</code></td>
<td>Cadastrar fornecedor</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/fornecedores/:id</code></td>
<td>Atualizar fornecedor</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/fornecedores/:id</code></td>
<td>Desativar</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/fornecedores/:id/certidoes</code></td>
<td>Upload de certidão</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/fornecedores/:id/certidoes</code></td>
<td>Listar certidões</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/fornecedores/:id/certidoes/:certidaoId</code></td>
<td>Remover certidão</td>
</tr>
</tbody>
</table>
<h3 id="57-demandas-apidemandas">5.7 Demandas (<code>/api/demandas</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/demandas</code></td>
<td>Listar demandas (filtros: status, local, categoria, período)</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/demandas/:id</code></td>
<td>Detalhes completos da demanda</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/demandas</code></td>
<td>Criar nova demanda</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/demandas/:id</code></td>
<td>Atualizar demanda</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/demandas/:id</code></td>
<td>Cancelar demanda</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/demandas/:id/itens</code></td>
<td>Adicionar item de linha</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/demandas/:id/itens/:itemId</code></td>
<td>Atualizar item</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/demandas/:id/itens/:itemId</code></td>
<td>Remover item</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/demandas/:id/enviar-cotacao</code></td>
<td>Enviar para cotação</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/demandas/:id/comparativo</code></td>
<td>Comparativo de propostas</td>
</tr>
</tbody>
</table>
<h3 id="58-propostas-apipropostas">5.8 Propostas (<code>/api/propostas</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/propostas</code></td>
<td>Listar propostas</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/propostas/:id</code></td>
<td>Detalhes da proposta</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/propostas</code></td>
<td>Submeter proposta (fornecedor)</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/propostas/:id</code></td>
<td>Atualizar proposta</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/propostas/:id</code></td>
<td>Retirar proposta</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/propostas/:id/aceitar</code></td>
<td>Aceitar proposta</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/propostas/:id/rejeitar</code></td>
<td>Rejeitar proposta</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/propostas/:id/ocr</code></td>
<td>Processar OCR do arquivo</td>
</tr>
</tbody>
</table>
<h3 id="59-orcamento-apiorcamento">5.9 Orçamento (<code>/api/orcamento</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/orcamento</code></td>
<td>Orçamento geral (filtros: ano, local, centro_custo)</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/orcamento/:id</code></td>
<td>Detalhes da linha orçamentária</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/orcamento</code></td>
<td>Criar linha orçamentária</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/orcamento/:id</code></td>
<td>Atualizar valores</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/orcamento/resumo</code></td>
<td>Resumo planejado vs realizado</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/orcamento/projecao</code></td>
<td>Projeção de gastos</td>
</tr>
</tbody>
</table>
<h3 id="510-workflow-apiworkflow">5.10 Workflow (<code>/api/workflow</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/workflow/pendentes</code></td>
<td>Aprovações pendentes do usuário logado</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/workflow/demanda/:demandaId</code></td>
<td>Histórico de aprovações da demanda</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/workflow/aprovar</code></td>
<td>Aprovar etapa</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/workflow/rejeitar</code></td>
<td>Rejeitar etapa</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/workflow/devolver</code></td>
<td>Devolver para correção</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/workflow/alçadas</code></td>
<td>Consultar alçadas configuradas</td>
</tr>
</tbody>
</table>
<h3 id="511-dashboard-apidashboard">5.11 Dashboard (<code>/api/dashboard</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/dashboard/indicadores</code></td>
<td>KPIs gerais</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/dashboard/demandas-por-status</code></td>
<td>Demandas agrupadas por status</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/dashboard/gastos-por-local</code></td>
<td>Gastos por unidade</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/dashboard/gastos-por-categoria</code></td>
<td>Gastos por categoria</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/dashboard/evolucao-mensal</code></td>
<td>Série temporal de gastos</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/dashboard/top-fornecedores</code></td>
<td>Ranking de fornecedores</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/dashboard/sla</code></td>
<td>Indicadores de SLA</td>
</tr>
</tbody>
</table>
<h3 id="512-ordens-de-servico-apiordens-servico">5.12 Ordens de Serviço (<code>/api/ordens-servico</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/ordens-servico</code></td>
<td>Listar OS</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/ordens-servico/:id</code></td>
<td>Detalhes da OS</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/ordens-servico</code></td>
<td>Emitir OS</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/ordens-servico/:id</code></td>
<td>Atualizar OS</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/ordens-servico/:id/iniciar</code></td>
<td>Marcar início da execução</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/ordens-servico/:id/concluir</code></td>
<td>Marcar conclusão</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/ordens-servico/:id/avaliar</code></td>
<td>Avaliar serviço prestado</td>
</tr>
</tbody>
</table>
<h3 id="513-alertas-apialertas">5.13 Alertas (<code>/api/alertas</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/alertas</code></td>
<td>Listar alertas do usuário</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/alertas/:id/lido</code></td>
<td>Marcar como lido</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/alertas/:id</code></td>
<td>Remover alerta</td>
</tr>
</tbody>
</table>
<h3 id="514-esg-sustentabilidade-apiesg">5.14 ESG / Sustentabilidade (<code>/api/esg</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/esg/metricas</code></td>
<td>Listar métricas ambientais (filtros: unidade, período, tipo)</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/esg/metricas</code></td>
<td>Registrar métrica ambiental</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/esg/metricas/:id</code></td>
<td>Atualizar métrica</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/esg/metricas/:id</code></td>
<td>Remover métrica</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/esg/dashboard</code></td>
<td>Dashboard consolidado ESG por unidade/período</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/esg/metas</code></td>
<td>Listar metas ESG</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/esg/metas</code></td>
<td>Criar meta ESG</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/esg/metas/:id</code></td>
<td>Atualizar meta ESG</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/esg/metas/:id/progresso</code></td>
<td>Progresso da meta ESG</td>
</tr>
</tbody>
</table>
<p><strong>Exemplo — POST <code>/api/esg/metricas</code>:</strong></p>
<pre><code class="language-json">// Request
{
&quot;local_id&quot;: 3,
&quot;tipo&quot;: &quot;energia&quot;,
&quot;valor&quot;: 12500.50,
&quot;unidade_medida&quot;: &quot;kWh&quot;,
&quot;periodo&quot;: &quot;2025-06&quot;,
&quot;observacoes&quot;: &quot;Consumo sede administrativa&quot;
}
// Response 201
{
&quot;id&quot;: 42,
&quot;local_id&quot;: 3,
&quot;tipo&quot;: &quot;energia&quot;,
&quot;valor&quot;: 12500.50,
&quot;unidade_medida&quot;: &quot;kWh&quot;,
&quot;periodo&quot;: &quot;2025-06&quot;,
&quot;created_at&quot;: &quot;2025-06-30T14:00:00Z&quot;
}
</code></pre>
<p><strong>Tipos de métricas suportados:</strong> <code>energia</code> (kWh), <code>agua</code> (m³), <code>residuos</code> (kg), <code>emissoes_co2</code> (tCO₂e).</p>
<h3 id="515-kpis-indicadores-de-performance-apikpis">5.15 KPIs — Indicadores de Performance (<code>/api/kpis</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/kpis</code></td>
<td>Listar KPIs calculados (filtros: categoria, ano, centro_custo)</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/kpis/dashboard</code></td>
<td>Dashboard de KPIs com status semáforo</td>
</tr>
</tbody>
</table>
<p><strong>KPIs calculados automaticamente:</strong></p>
<table>
<thead>
<tr>
<th>KPI</th>
<th>Fórmula</th>
<th>Verde</th>
<th>Amarelo</th>
<th>Vermelho</th>
</tr>
</thead>
<tbody>
<tr>
<td>% Orçamento Consumido</td>
<td>realizado / planejado × 100</td>
<td>≤ 80%</td>
<td>81100%</td>
<td>&gt; 100%</td>
</tr>
<tr>
<td>Tempo Médio de OS</td>
<td>média(data_fim_real - data_inicio)</td>
<td>≤ SLA</td>
<td>SLA+20%</td>
<td>&gt; SLA+20%</td>
</tr>
<tr>
<td>Rating Fornecedores</td>
<td>média das avaliações</td>
<td>≥ 4.0</td>
<td>3.03.9</td>
<td>&lt; 3.0</td>
</tr>
<tr>
<td>Taxa Conclusão Demandas</td>
<td>concluídas / total × 100</td>
<td>≥ 90%</td>
<td>7089%</td>
<td>&lt; 70%</td>
</tr>
</tbody>
</table>
<p><strong>Exemplo — GET <code>/api/kpis/dashboard</code>:</strong></p>
<pre><code class="language-json">// Response 200
{
&quot;periodo&quot;: &quot;2025-06&quot;,
&quot;kpis&quot;: [
{
&quot;nome&quot;: &quot;orcamento_consumido&quot;,
&quot;valor&quot;: 78.5,
&quot;unidade&quot;: &quot;%&quot;,
&quot;status&quot;: &quot;verde&quot;,
&quot;centro_custo&quot;: &quot;ADM-001&quot;
},
{
&quot;nome&quot;: &quot;tempo_medio_os&quot;,
&quot;valor&quot;: 12.3,
&quot;unidade&quot;: &quot;dias&quot;,
&quot;status&quot;: &quot;amarelo&quot;,
&quot;centro_custo&quot;: &quot;ADM-001&quot;
}
]
}
</code></pre>
<h3 id="516-auditoria-e-compliance-apiaudit">5.16 Auditoria e Compliance (<code>/api/audit</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/audit/logs</code></td>
<td>Trilha de auditoria completa (filtros: usuario, entidade, período, ação)</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/audit/compliance-report</code></td>
<td>Relatório de conformidade por período</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/audit/export</code></td>
<td>Exportação de logs em CSV ou JSON (<code>?format=csv\|json</code>)</td>
</tr>
</tbody>
</table>
<p><strong>Exemplo — GET <code>/api/audit/logs?entidade=demandas&amp;periodo_inicio=2025-06-01</code>:</strong></p>
<pre><code class="language-json">// Response 200
{
&quot;total&quot;: 245,
&quot;page&quot;: 1,
&quot;data&quot;: [
{
&quot;id&quot;: 1023,
&quot;usuario&quot;: &quot;joao.silva@empresa.com&quot;,
&quot;acao&quot;: &quot;UPDATE&quot;,
&quot;entidade&quot;: &quot;demandas&quot;,
&quot;entidade_id&quot;: 87,
&quot;dados_antes&quot;: { &quot;status&quot;: &quot;EM_COTACAO&quot; },
&quot;dados_depois&quot;: { &quot;status&quot;: &quot;PROPOSTAS_RECEBIDAS&quot; },
&quot;ip&quot;: &quot;192.168.1.50&quot;,
&quot;created_at&quot;: &quot;2025-06-15T10:32:00Z&quot;
}
]
}
</code></pre>
<h3 id="517-importacao-de-dados-apiimport">5.17 Importação de Dados (<code>/api/import</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST</td>
<td><code>/api/import/excel</code></td>
<td>Upload de planilha Excel/CSV com validação automática</td>
</tr>
</tbody>
</table>
<p><strong>Tipos de importação:</strong> <code>orcamento</code>, <code>demandas</code>.</p>
<p><strong>Exemplo — POST <code>/api/import/excel</code> (multipart/form-data):</strong></p>
<pre><code class="language-json">// Request: file=planilha.xlsx, tipo=orcamento
// Response 200
{
&quot;status&quot;: &quot;success&quot;,
&quot;registros_importados&quot;: 48,
&quot;registros_com_erro&quot;: 2,
&quot;erros&quot;: [
{ &quot;linha&quot;: 15, &quot;campo&quot;: &quot;valor_planejado&quot;, &quot;mensagem&quot;: &quot;Valor inválido&quot; },
{ &quot;linha&quot;: 32, &quot;campo&quot;: &quot;centro_custo_id&quot;, &quot;mensagem&quot;: &quot;Centro de custo não encontrado&quot; }
]
}
</code></pre>
<h3 id="518-relatorios-automatizados-apirelatorios">5.18 Relatórios Automatizados (<code>/api/relatorios</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/relatorios/orcamento-mensal</code></td>
<td>Relatório de orçamento mensal (filtros: ano, mês, local)</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/relatorios/demandas-periodo</code></td>
<td>Demandas por período com status e valores</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/relatorios/fornecedores-ranking</code></td>
<td>Ranking de fornecedores com nota, valor e volume</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/relatorios/os-performance</code></td>
<td>Performance de OS (SLA, tempo médio, conclusão)</td>
</tr>
</tbody>
</table>
<p><strong>Todos os relatórios suportam <code>?format=json|csv|pdf</code>.</strong></p>
<p><strong>Exemplo — GET <code>/api/relatorios/fornecedores-ranking?ano=2025&amp;limit=10</code>:</strong></p>
<pre><code class="language-json">// Response 200
{
&quot;periodo&quot;: &quot;2025&quot;,
&quot;ranking&quot;: [
{
&quot;posicao&quot;: 1,
&quot;fornecedor&quot;: &quot;TechServ Ltda&quot;,
&quot;rating&quot;: 4.8,
&quot;total_os&quot;: 23,
&quot;valor_total&quot;: 187500.00,
&quot;sla_cumprido&quot;: 95.6
}
]
}
</code></pre>
<h3 id="519-metas-e-progresso-apimetas">5.19 Metas e Progresso (<code>/api/metas</code>)</h3>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>GET</td>
<td><code>/api/metas</code></td>
<td>Listar metas (filtros: centro_custo, tipo, status)</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/metas</code></td>
<td>Criar meta</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/metas/:id</code></td>
<td>Atualizar meta</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/metas/:id</code></td>
<td>Remover meta</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/metas/progresso</code></td>
<td>Progresso geral de todas as metas</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/metas/:id/progresso</code></td>
<td>Progresso de meta específica</td>
</tr>
</tbody>
</table>
<p><strong>Tipos de meta:</strong> <code>orcamento</code>, <code>operacional</code>, <code>esg</code>.</p>
<p><strong>Status:</strong> <code>em_andamento</code>, <code>atingida</code>, <code>atrasada</code>.</p>
<p><strong>Exemplo — POST <code>/api/metas</code>:</strong></p>
<pre><code class="language-json">// Request
{
&quot;centro_custo_id&quot;: 5,
&quot;tipo&quot;: &quot;orcamento&quot;,
&quot;descricao&quot;: &quot;Reduzir gastos com manutenção em 10%&quot;,
&quot;valor_alvo&quot;: 90,
&quot;unidade&quot;: &quot;%&quot;,
&quot;prazo&quot;: &quot;2025-12-31&quot;
}
// Response 201
{
&quot;id&quot;: 12,
&quot;centro_custo_id&quot;: 5,
&quot;tipo&quot;: &quot;orcamento&quot;,
&quot;descricao&quot;: &quot;Reduzir gastos com manutenção em 10%&quot;,
&quot;valor_alvo&quot;: 90,
&quot;valor_atual&quot;: 0,
&quot;percentual_atingido&quot;: 0,
&quot;status&quot;: &quot;em_andamento&quot;,
&quot;prazo&quot;: &quot;2025-12-31&quot;,
&quot;created_at&quot;: &quot;2025-02-09T15:00:00Z&quot;
}
</code></pre>
<h3 id="520-alertas-inteligentes-apialertas">5.20 Alertas Inteligentes (<code>/api/alertas</code>)</h3>
<blockquote>
<p><strong>Nota:</strong> Os endpoints abaixo complementam os alertas básicos da seção 5.13 com configuração avançada e verificação automática.</p>
</blockquote>
<table>
<thead>
<tr>
<th>Método</th>
<th>Rota</th>
<th>Descrição</th>
</tr>
</thead>
<tbody>
<tr>
<td>POST</td>
<td><code>/api/alertas/configurar</code></td>
<td>Configurar regra de alerta inteligente</td>
</tr>
<tr>
<td>GET</td>
<td><code>/api/alertas/configurar</code></td>
<td>Listar configurações de alertas</td>
</tr>
<tr>
<td>PATCH</td>
<td><code>/api/alertas/configurar/:id</code></td>
<td>Atualizar configuração</td>
</tr>
<tr>
<td>DELETE</td>
<td><code>/api/alertas/configurar/:id</code></td>
<td>Remover configuração</td>
</tr>
<tr>
<td>POST</td>
<td><code>/api/alertas/verificar</code></td>
<td>Disparar verificação manual de todos os alertas</td>
</tr>
</tbody>
</table>
<p><strong>Tipos de alerta:</strong> <code>orcamento_excedido</code>, <code>certidao_vencendo</code>, <code>os_atrasada</code>, <code>meta_em_risco</code>.</p>
<p><strong>Exemplo — POST <code>/api/alertas/configurar</code>:</strong></p>
<pre><code class="language-json">// Request
{
&quot;tipo&quot;: &quot;orcamento_excedido&quot;,
&quot;centro_custo_id&quot;: 5,
&quot;limite_percentual&quot;: 85,
&quot;notificar_usuarios&quot;: [1, 3, 7],
&quot;ativo&quot;: true
}
// Response 201
{
&quot;id&quot;: 8,
&quot;tipo&quot;: &quot;orcamento_excedido&quot;,
&quot;centro_custo_id&quot;: 5,
&quot;limite_percentual&quot;: 85,
&quot;notificar_usuarios&quot;: [1, 3, 7],
&quot;ativo&quot;: true,
&quot;created_at&quot;: &quot;2025-02-09T15:00:00Z&quot;
}
</code></pre>
<p><strong>Total: 95 endpoints</strong></p>
<h2 id="6-autenticacao-e-autorizacao">6. Autenticação e Autorização</h2>
<h3 id="61-fluxo-jwt">6.1 Fluxo JWT</h3>
<ol>
<li>Usuário faz POST <code>/api/auth/login</code> com email e senha</li>
<li>Backend valida credenciais e retorna <code>{ accessToken, refreshToken }</code></li>
<li>Frontend armazena tokens e envia <code>Authorization: Bearer &lt;accessToken&gt;</code> em todas as requests</li>
<li>Token expira em 1h; refresh token expira em 7d</li>
<li>Frontend usa <code>/api/auth/refresh</code> para renovar automaticamente</li>
</ol>
<h3 id="62-guards-nestjs">6.2 Guards NestJS</h3>
<pre><code class="language-typescript">@UseGuards(JwtAuthGuard, RolesGuard)
@Roles('admin', 'gestor_facilities')
@Get('demandas')
findAll() { ... }
</code></pre>
<ul>
<li><strong>JwtAuthGuard</strong>: valida o token JWT</li>
<li><strong>RolesGuard</strong>: verifica se o perfil do usuário está na lista de roles permitidas</li>
<li><strong>@CurrentUser()</strong>: decorator customizado que injeta o usuário logado</li>
</ul>
<h2 id="7-workflow-de-aprovacao">7. Workflow de Aprovação</h2>
<h3 id="71-maquina-de-estados">7.1 Máquina de Estados</h3>
<pre><code>RASCUNHO → EM_ESCOPO → EM_COTAÇÃO → PROPOSTAS_RECEBIDAS
→ EM_COMPARAÇÃO → AGUARDANDO_APROVAÇÃO → APROVADA
→ OS_EMITIDA → EM_EXECUÇÃO → CONCLUÍDA → AVALIADA
Estados alternativos:
AGUARDANDO_APROVAÇÃO → REJEITADA
AGUARDANDO_APROVAÇÃO → DEVOLVIDA → EM_ESCOPO
Qualquer estado → CANCELADA
</code></pre>
<h3 id="72-alcadas-de-aprovacao">7.2 Alçadas de Aprovação</h3>
<table>
<thead>
<tr>
<th>Faixa de Valor</th>
<th>Aprovador</th>
</tr>
</thead>
<tbody>
<tr>
<td>Até R$ 5.000</td>
<td>Gestor Facilities</td>
</tr>
<tr>
<td>R$ 5.001 — R$ 50.000</td>
<td>Gestor Facilities + Aprovador Financeiro</td>
</tr>
<tr>
<td>R$ 50.001 — R$ 200.000</td>
<td>Gestor + Financeiro + Diretoria</td>
</tr>
<tr>
<td>Acima de R$ 200.000</td>
<td>Gestor + Financeiro + Diretoria + CEO</td>
</tr>
</tbody>
</table>
<p>Cada etapa gera um registro em <code>workflow_aprovacao</code> com timestamp, aprovador e comentário.</p>
<h2 id="8-como-rodar-localmente">8. Como Rodar Localmente</h2>
<h3 id="81-pre-requisitos">8.1 Pré-requisitos</h3>
<ul>
<li>Node.js 22.x</li>
<li>npm 10.x</li>
<li>Git</li>
</ul>
<h3 id="82-backend">8.2 Backend</h3>
<pre><code class="language-bash">cd backend
cp .env.example .env # Ajustar variáveis
npm install
npm run build
npm run migration:run # Criar tabelas
npm run seed # Dados iniciais
npm start # Porta 3000
</code></pre>
<h3 id="83-frontend">8.3 Frontend</h3>
<pre><code class="language-bash">cd frontend
cp .env.example .env # VITE_API_URL=http://localhost:3000/api
npm install
npm run dev # Porta 5173
</code></pre>
<h3 id="84-acesso-inicial">8.4 Acesso Inicial</h3>
<ul>
<li><strong>Admin:</strong> admin@hefesto.com.br / admin123</li>
<li><strong>Swagger:</strong> http://localhost:3000/api/docs</li>
</ul>
<h2 id="9-deploy-em-producao">9. Deploy em Produção</h2>
<h3 id="91-infraestrutura">9.1 Infraestrutura</h3>
<ul>
<li><strong>Servidor:</strong> DigitalOcean Droplet (Ubuntu 24.04, 2 vCPU, 4GB RAM)</li>
<li><strong>Proxy reverso:</strong> Nginx</li>
<li><strong>SSL:</strong> Let's Encrypt (Certbot)</li>
<li><strong>Processo:</strong> PM2 (backend) / Nginx serve build estático (frontend)</li>
<li><strong>BD:</strong> PostgreSQL 16</li>
</ul>
<h3 id="92-nginx-config">9.2 Nginx Config</h3>
<pre><code class="language-nginx">server {
listen 443 ssl;
server_name hefesto.exemplo.com.br;
ssl_certificate /etc/letsencrypt/live/hefesto.exemplo.com.br/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/hefesto.exemplo.com.br/privkey.pem;
# Frontend (build estático)
location / {
root /var/www/hefesto/frontend/dist;
try_files $uri $uri/ /index.html;
}
# API Backend
location /api {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
</code></pre>
<h3 id="93-pm2">9.3 PM2</h3>
<pre><code class="language-bash">cd /var/www/hefesto/backend
pm2 start dist/main.js --name hefesto-api
pm2 save
pm2 startup
</code></pre>
<h2 id="10-variaveis-de-ambiente">10. Variáveis de Ambiente</h2>
<h3 id="backend-env">Backend (<code>.env</code>)</h3>
<table>
<thead>
<tr>
<th>Variável</th>
<th>Descrição</th>
<th>Exemplo</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>NODE_ENV</code></td>
<td>Ambiente</td>
<td><code>production</code></td>
</tr>
<tr>
<td><code>PORT</code></td>
<td>Porta da API</td>
<td><code>3000</code></td>
</tr>
<tr>
<td><code>DB_TYPE</code></td>
<td>Tipo de banco</td>
<td><code>postgres</code></td>
</tr>
<tr>
<td><code>DB_HOST</code></td>
<td>Host do banco</td>
<td><code>localhost</code></td>
</tr>
<tr>
<td><code>DB_PORT</code></td>
<td>Porta do banco</td>
<td><code>5432</code></td>
</tr>
<tr>
<td><code>DB_USERNAME</code></td>
<td>Usuário do banco</td>
<td><code>hefesto</code></td>
</tr>
<tr>
<td><code>DB_PASSWORD</code></td>
<td>Senha do banco</td>
<td><code>***</code></td>
</tr>
<tr>
<td><code>DB_DATABASE</code></td>
<td>Nome do banco</td>
<td><code>hefesto_prod</code></td>
</tr>
<tr>
<td><code>JWT_SECRET</code></td>
<td>Chave secreta JWT</td>
<td><code>minha-chave-secreta-256bits</code></td>
</tr>
<tr>
<td><code>JWT_EXPIRATION</code></td>
<td>Tempo de expiração do access token</td>
<td><code>3600s</code></td>
</tr>
<tr>
<td><code>JWT_REFRESH_EXPIRATION</code></td>
<td>Tempo de expiração do refresh token</td>
<td><code>7d</code></td>
</tr>
<tr>
<td><code>CORS_ORIGIN</code></td>
<td>Origem permitida</td>
<td><code>https://hefesto.exemplo.com.br</code></td>
</tr>
<tr>
<td><code>OCR_API_KEY</code></td>
<td>Chave da API de OCR</td>
<td><code>***</code></td>
</tr>
<tr>
<td><code>SMTP_HOST</code></td>
<td>Servidor SMTP</td>
<td><code>smtp.gmail.com</code></td>
</tr>
<tr>
<td><code>SMTP_PORT</code></td>
<td>Porta SMTP</td>
<td><code>587</code></td>
</tr>
<tr>
<td><code>SMTP_USER</code></td>
<td>Usuário SMTP</td>
<td><code>noreply@hefesto.com.br</code></td>
</tr>
<tr>
<td><code>SMTP_PASS</code></td>
<td>Senha SMTP</td>
<td><code>***</code></td>
</tr>
</tbody>
</table>
<h3 id="frontend-env">Frontend (<code>.env</code>)</h3>
<table>
<thead>
<tr>
<th>Variável</th>
<th>Descrição</th>
<th>Exemplo</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>VITE_API_URL</code></td>
<td>URL base da API</td>
<td><code>https://hefesto.exemplo.com.br/api</code></td>
</tr>
<tr>
<td><code>VITE_APP_NAME</code></td>
<td>Nome da aplicação</td>
<td><code>HEFESTO</code></td>
</tr>
</tbody>
</table>
<hr />
<p><em>Documento gerado automaticamente — HEFESTO v2.0</em></p>
</div>
<div class="doc-footer">
HEFESTO v2.0 &nbsp;·&nbsp; Kislanski Industries | AI Vertice &nbsp;·&nbsp; Fevereiro 2026<br>
Documento confidencial — Todos os direitos reservados
</div>
</body>
</html>