Files
hefesto/docs/ARQUITETURA-TECNICA.md
bigtux d8ca580acb HEFESTO v1.0 - Sistema de Controle Orçamentário para Facilities
- Backend NestJS com 12 módulos
- Frontend React com dashboard e gestão
- Manuais técnico e de negócios (MD + PDF)
- Workflow de aprovação com alçadas
- RBAC com 6 perfis de acesso
2026-02-09 14:53:01 -03:00

47 KiB

HEFESTO — Arquitetura Técnica

Sistema de Controle Orçamentário para Facilities

Versão: 1.0
Data: 2026-02-09
Stack: NestJS · React · PostgreSQL


1. Visão Geral da Arquitetura

┌─────────────────────────────────────────────────────────────────────┐
│                        CLIENTE (Browser)                            │
│  ┌───────────────────────────────────────────────────────────────┐  │
│  │              React + Vite (SPA)                               │  │
│  │  ┌──────┐ ┌──────────┐ ┌──────────┐ ┌─────────┐ ┌────────┐  │  │
│  │  │ Auth │ │Dashboard │ │Demandas  │ │Propostas│ │Relat.  │  │  │
│  │  └──────┘ └──────────┘ └──────────┘ └─────────┘ └────────┘  │  │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────────────┐│  │
│  │  │Orçamento │ │Fornec.   │ │Workflow  │ │Ordens de Serviço ││  │
│  │  └──────────┘ └──────────┘ └──────────┘ └──────────────────┘│  │
│  └───────────────────────────────────────────────────────────────┘  │
└────────────────────────────┬────────────────────────────────────────┘
                             │ HTTPS / REST + JWT
┌────────────────────────────▼────────────────────────────────────────┐
│                      API GATEWAY (NestJS)                           │
│  ┌────────┐ ┌──────┐ ┌──────────┐ ┌──────────┐ ┌───────────────┐  │
│  │  Auth  │ │Users │ │  Locais  │ │Categorias│ │ Fornecedores  │  │
│  └────────┘ └──────┘ └──────────┘ └──────────┘ └───────────────┘  │
│  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌────────┐  │
│  │Demandas  │ │Propostas │ │Orçamento │ │Workflow  │ │  OCR   │  │
│  └──────────┘ └──────────┘ └──────────┘ └──────────┘ └────────┘  │
│  ┌───────────────┐ ┌──────────┐ ┌──────────────────────────────┐  │
│  │Ordens Serviço │ │Dashboard │ │       Relatórios             │  │
│  └───────────────┘ └──────────┘ └──────────────────────────────┘  │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │  Guards (JWT + RBAC) │ Interceptors │ Pipes │ Audit Logger  │   │
│  └─────────────────────────────────────────────────────────────┘   │
└────────────────────────────┬────────────────────────────────────────┘
              ┌──────────────┼──────────────┐
              ▼              ▼              ▼
     ┌────────────┐  ┌────────────┐  ┌────────────┐
     │ PostgreSQL │  │   Redis    │  │  Storage   │
     │  (dados)   │  │  (cache/   │  │  (S3/MinIO │
     │            │  │   filas)   │  │   PDFs)    │
     └────────────┘  └────────────┘  └────────────┘
                                          │
                                     ┌────▼─────┐
                                     │ OpenAI   │
                                     │GPT-4o-   │
                                     │  mini    │
                                     └──────────┘

2. Modelo de Dados Completo

2.1 Diagrama Entidade-Relacionamento (textual)

perfis ──1:N──> usuarios
locais ──1:N──> demandas
centros_custo ──1:N──> demandas
centros_custo ──1:N──> orcamento_planejado
categorias ──1:N──> demandas
categorias ──1:N──> orcamento_planejado
fornecedores ──1:N──> certidoes
fornecedores ──1:N──> propostas
demandas ──1:N──> itens_linha
demandas ──1:N──> propostas
demandas ──1:1──> workflow_aprovacao
demandas ──1:1──> ordens_servico
propostas ──1:N──> versoes_proposta
demandas ──1:1──> comparativo_propostas
ordens_servico ──1:1──> avaliacoes
matriz_alcada ──> centros_custo, perfis

2.2 Tabelas

perfis

Coluna Tipo Restrições
id UUID PK, DEFAULT gen_random_uuid()
nome VARCHAR(50) NOT NULL, UNIQUE
descricao TEXT
permissoes JSONB NOT NULL, DEFAULT '{}'
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()

Valores seed: solicitante, gestor_facilities, aprovador_financeiro, diretoria, fornecedor, administrador

usuarios

Coluna Tipo Restrições
id UUID PK
nome VARCHAR(200) NOT NULL
email VARCHAR(255) NOT NULL, UNIQUE
senha_hash VARCHAR(255) NOT NULL
perfil_id UUID FK → perfis.id, NOT NULL
ativo BOOLEAN DEFAULT TRUE
ultimo_acesso TIMESTAMPTZ
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()

locais

Coluna Tipo Restrições
id UUID PK
nome VARCHAR(200) NOT NULL
endereco TEXT
centro_custo_id UUID FK → centros_custo.id, NOT NULL
responsavel_id UUID FK → usuarios.id
ativo BOOLEAN DEFAULT TRUE
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()

centros_custo

Coluna Tipo Restrições
id UUID PK
codigo VARCHAR(20) NOT NULL, UNIQUE
nome VARCHAR(200) NOT NULL
responsavel_id UUID FK → usuarios.id
ativo BOOLEAN DEFAULT TRUE
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()

categorias

Coluna Tipo Restrições
id UUID PK
nome VARCHAR(200) NOT NULL
subcategoria VARCHAR(200)
criticidade_padrao VARCHAR(20) CHECK (criticidade_padrao IN ('baixa','media','alta','critica'))
sla_dias INTEGER DEFAULT 30
categoria_pai_id UUID FK → categorias.id (auto-ref)
ativo BOOLEAN DEFAULT TRUE
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()

fornecedores

Coluna Tipo Restrições
id UUID PK
tipo_pessoa VARCHAR(10) NOT NULL, CHECK (tipo_pessoa IN ('PF','PJ'))
cpf_cnpj VARCHAR(18) NOT NULL, UNIQUE
razao_social VARCHAR(300) NOT NULL
nome_fantasia VARCHAR(300)
email VARCHAR(255)
telefone VARCHAR(20)
endereco TEXT
categorias_atendidas UUID[] (array de FK → categorias.id)
rating NUMERIC(2,1) DEFAULT 3.0, CHECK (rating >= 1 AND rating <= 5)
usuario_id UUID FK → usuarios.id (login do portal)
ativo BOOLEAN DEFAULT TRUE
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()

certidoes

Coluna Tipo Restrições
id UUID PK
fornecedor_id UUID FK → fornecedores.id, NOT NULL
tipo VARCHAR(100) NOT NULL
numero VARCHAR(100)
data_emissao DATE NOT NULL
data_validade DATE NOT NULL
arquivo_url TEXT
status VARCHAR(20) CHECK (status IN ('vigente','vencida','pendente'))
created_at TIMESTAMPTZ DEFAULT NOW()

orcamento_planejado

Coluna Tipo Restrições
id UUID PK
ano INTEGER NOT NULL
mes INTEGER NOT NULL, CHECK (mes BETWEEN 1 AND 12)
centro_custo_id UUID FK → centros_custo.id, NOT NULL
categoria_id UUID FK → categorias.id, NOT NULL
valor_planejado NUMERIC(15,2) NOT NULL
valor_comprometido NUMERIC(15,2) DEFAULT 0
valor_realizado NUMERIC(15,2) DEFAULT 0
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()
UNIQUE(ano, mes, centro_custo_id, categoria_id)

demandas

Coluna Tipo Restrições
id UUID PK
numero SERIAL UNIQUE (código sequencial)
titulo VARCHAR(300) NOT NULL
descricao TEXT
local_id UUID FK → locais.id, NOT NULL
centro_custo_id UUID FK → centros_custo.id, NOT NULL
categoria_id UUID FK → categorias.id, NOT NULL
criticidade VARCHAR(20) NOT NULL, CHECK (... IN ('baixa','media','alta','critica'))
data_desejada DATE
status VARCHAR(30) NOT NULL, DEFAULT 'rascunho'
solicitante_id UUID FK → usuarios.id, NOT NULL
gestor_id UUID FK → usuarios.id
documentos JSONB DEFAULT '[]'
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()

Status possíveis: rascunho, aberta, em_escopo, em_cotacao, propostas_recebidas, em_comparacao, em_aprovacao, aprovada, os_emitida, em_execucao, concluida, cancelada

itens_linha

Coluna Tipo Restrições
id UUID PK
demanda_id UUID FK → demandas.id, NOT NULL
descricao VARCHAR(300) NOT NULL
tipo VARCHAR(50) CHECK (tipo IN ('mao_de_obra','material','equipamento','outros'))
quantidade NUMERIC(10,2)
unidade VARCHAR(30)
observacoes TEXT
ordem INTEGER DEFAULT 0
created_at TIMESTAMPTZ DEFAULT NOW()

propostas

Coluna Tipo Restrições
id UUID PK
demanda_id UUID FK → demandas.id, NOT NULL
fornecedor_id UUID FK → fornecedores.id, NOT NULL
versao_atual INTEGER DEFAULT 1
valor_bruto NUMERIC(15,2)
valor_liquido NUMERIC(15,2)
impostos JSONB DEFAULT '{}' (iss, inss, pcc)
condicao_pagamento TEXT
prazo_execucao_dias INTEGER
data_entrega_estimada DATE
match_escopo_pct NUMERIC(5,2)
confiabilidade_ocr NUMERIC(5,2)
selecionada BOOLEAN DEFAULT FALSE
status VARCHAR(20) DEFAULT 'recebida'
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()

versoes_proposta

Coluna Tipo Restrições
id UUID PK
proposta_id UUID FK → propostas.id, NOT NULL
versao INTEGER NOT NULL
arquivo_url TEXT NOT NULL
arquivo_nome VARCHAR(300)
dados_extraidos JSONB (resultado bruto do OCR)
dados_parseados JSONB (resultado estruturado)
confiabilidade NUMERIC(5,2)
uploaded_by UUID FK → usuarios.id
created_at TIMESTAMPTZ DEFAULT NOW()

comparativo_propostas

Coluna Tipo Restrições
id UUID PK
demanda_id UUID FK → demandas.id, NOT NULL, UNIQUE
propostas_ids UUID[] NOT NULL
benchmark_id UUID FK → propostas.id
dados_comparativo JSONB NOT NULL
anotacoes JSONB DEFAULT '[]'
gerado_em TIMESTAMPTZ DEFAULT NOW()
atualizado_em TIMESTAMPTZ DEFAULT NOW()

workflow_aprovacao

Coluna Tipo Restrições
id UUID PK
demanda_id UUID FK → demandas.id, NOT NULL
proposta_id UUID FK → propostas.id, NOT NULL
valor_total NUMERIC(15,2) NOT NULL
status VARCHAR(30) NOT NULL, DEFAULT 'pendente'
etapa_atual INTEGER DEFAULT 1
etapas JSONB NOT NULL (array de etapas)
emergencial BOOLEAN DEFAULT FALSE
justificativa_emergencial TEXT
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()

Status: pendente, em_andamento, aprovado, reprovado, aprovado_com_ressalva, cancelado

Estrutura de etapas (JSONB):

[
  {
    "ordem": 1,
    "perfil": "gestor_facilities",
    "aprovador_id": "uuid",
    "status": "aprovado",
    "data_acao": "2026-01-15T10:00:00Z",
    "observacao": "OK",
    "ressalva": false
  },
  {
    "ordem": 2,
    "perfil": "aprovador_financeiro",
    "aprovador_id": null,
    "status": "pendente",
    "data_acao": null,
    "observacao": null,
    "ressalva": false
  }
]

matriz_alcada

Coluna Tipo Restrições
id UUID PK
centro_custo_id UUID FK → centros_custo.id
valor_minimo NUMERIC(15,2) NOT NULL
valor_maximo NUMERIC(15,2) NOT NULL
perfil_aprovador VARCHAR(50) NOT NULL
ordem_sequencial INTEGER DEFAULT 1
ativo BOOLEAN DEFAULT TRUE
created_at TIMESTAMPTZ DEFAULT NOW()

ordens_servico

Coluna Tipo Restrições
id UUID PK
numero SERIAL UNIQUE
demanda_id UUID FK → demandas.id, NOT NULL, UNIQUE
proposta_id UUID FK → propostas.id, NOT NULL
fornecedor_id UUID FK → fornecedores.id, NOT NULL
valor NUMERIC(15,2) NOT NULL
status VARCHAR(30) DEFAULT 'emitida'
data_emissao TIMESTAMPTZ DEFAULT NOW()
data_inicio DATE
data_conclusao DATE
observacoes TEXT
created_at TIMESTAMPTZ DEFAULT NOW()
updated_at TIMESTAMPTZ DEFAULT NOW()

Status: emitida, em_execucao, concluida, cancelada

avaliacoes

Coluna Tipo Restrições
id UUID PK
ordem_servico_id UUID FK → ordens_servico.id, NOT NULL, UNIQUE
fornecedor_id UUID FK → fornecedores.id, NOT NULL
avaliador_id UUID FK → usuarios.id, NOT NULL
nota NUMERIC(2,1) NOT NULL, CHECK (nota >= 1 AND nota <= 5)
comentario TEXT
created_at TIMESTAMPTZ DEFAULT NOW()

audit_log

Coluna Tipo Restrições
id UUID PK
usuario_id UUID FK → usuarios.id
acao VARCHAR(50) NOT NULL
entidade VARCHAR(50) NOT NULL
entidade_id UUID
dados_antes JSONB
dados_depois JSONB
ip VARCHAR(45)
user_agent TEXT
created_at TIMESTAMPTZ DEFAULT NOW()

Índice: CREATE INDEX idx_audit_log_entidade ON audit_log(entidade, entidade_id); Índice: CREATE INDEX idx_audit_log_usuario ON audit_log(usuario_id, created_at DESC);

alertas

Coluna Tipo Restrições
id UUID PK
usuario_id UUID FK → usuarios.id, NOT NULL
tipo VARCHAR(50) NOT NULL
titulo VARCHAR(300) NOT NULL
mensagem TEXT
entidade VARCHAR(50)
entidade_id UUID
lido BOOLEAN DEFAULT FALSE
created_at TIMESTAMPTZ DEFAULT NOW()

Tipos de alerta: estouro_orcamento, sla_vencendo, proposta_pendente, aprovacao_pendente, certidao_vencendo, os_atrasada


3. Módulos NestJS

3.1 Estrutura de Pastas

src/
├── main.ts
├── app.module.ts
├── common/
│   ├── decorators/          # @Roles(), @CurrentUser(), @Audit()
│   ├── guards/              # JwtAuthGuard, RolesGuard
│   ├── interceptors/        # AuditInterceptor, TransformInterceptor
│   ├── pipes/               # ParseUUIDPipe, ValidationPipe
│   ├── filters/             # HttpExceptionFilter
│   ├── dto/                 # PaginationDto, FilterDto
│   └── interfaces/          # ICurrentUser, IPaginatedResult
├── config/
│   ├── database.config.ts
│   ├── jwt.config.ts
│   ├── storage.config.ts
│   └── openai.config.ts
├── modules/
│   ├── auth/
│   │   ├── auth.module.ts
│   │   ├── auth.controller.ts
│   │   ├── auth.service.ts
│   │   ├── strategies/      # JwtStrategy, LocalStrategy
│   │   ├── dto/             # LoginDto, RegisterDto, RefreshTokenDto
│   │   └── guards/
│   ├── users/
│   │   ├── users.module.ts
│   │   ├── users.controller.ts
│   │   ├── users.service.ts
│   │   ├── entities/        # User, Perfil
│   │   └── dto/
│   ├── locais/
│   │   ├── locais.module.ts
│   │   ├── locais.controller.ts
│   │   ├── locais.service.ts
│   │   ├── entities/        # Local, CentroCusto
│   │   └── dto/
│   ├── categorias/
│   │   ├── categorias.module.ts
│   │   ├── categorias.controller.ts
│   │   ├── categorias.service.ts
│   │   ├── entities/        # Categoria
│   │   └── dto/
│   ├── fornecedores/
│   │   ├── fornecedores.module.ts
│   │   ├── fornecedores.controller.ts
│   │   ├── fornecedores.service.ts
│   │   ├── entities/        # Fornecedor, Certidao
│   │   └── dto/
│   ├── demandas/
│   │   ├── demandas.module.ts
│   │   ├── demandas.controller.ts
│   │   ├── demandas.service.ts
│   │   ├── entities/        # Demanda, ItemLinha
│   │   └── dto/
│   ├── propostas/
│   │   ├── propostas.module.ts
│   │   ├── propostas.controller.ts
│   │   ├── propostas.service.ts
│   │   ├── entities/        # Proposta, VersaoProposta, ComparativoPropostas
│   │   └── dto/
│   ├── orcamento/
│   │   ├── orcamento.module.ts
│   │   ├── orcamento.controller.ts
│   │   ├── orcamento.service.ts
│   │   ├── entities/        # OrcamentoPlanejado
│   │   └── dto/
│   ├── workflow/
│   │   ├── workflow.module.ts
│   │   ├── workflow.controller.ts
│   │   ├── workflow.service.ts
│   │   ├── entities/        # WorkflowAprovacao, MatrizAlcada
│   │   └── dto/
│   ├── ordens-servico/
│   │   ├── ordens-servico.module.ts
│   │   ├── ordens-servico.controller.ts
│   │   ├── ordens-servico.service.ts
│   │   ├── entities/        # OrdemServico, Avaliacao
│   │   └── dto/
│   ├── ocr/
│   │   ├── ocr.module.ts
│   │   ├── ocr.service.ts
│   │   ├── ocr.processor.ts       # Bull queue processor
│   │   ├── prompts/                # System prompts para GPT-4o-mini
│   │   └── interfaces/
│   ├── dashboard/
│   │   ├── dashboard.module.ts
│   │   ├── dashboard.controller.ts
│   │   └── dashboard.service.ts
│   └── relatorios/
│       ├── relatorios.module.ts
│       ├── relatorios.controller.ts
│       ├── relatorios.service.ts
│       └── templates/              # Templates PDF/Excel
└── database/
    ├── migrations/
    └── seeds/

3.2 Dependências entre Módulos

                    ┌──────────┐
                    │   Auth   │
                    └────┬─────┘
                         │ JWT/Guards
          ┌──────────────┼──────────────────┐
          ▼              ▼                  ▼
     ┌────────┐    ┌──────────┐       ┌──────────┐
     │ Users  │    │Dashboard │       │Relatórios│
     └────────┘    └──────────┘       └──────────┘
                        │ agrega            │ lê
     ┌──────────────────┼──────────────┐    │
     ▼         ▼        ▼             ▼    ▼
┌────────┐┌────────┐┌──────────┐┌──────────┐
│ Locais ││Categ.  ││Demandas  ││Orçamento │
└────────┘└────────┘└─────┬────┘└──────────┘
                          │
              ┌───────────┼───────────┐
              ▼           ▼           ▼
        ┌──────────┐┌──────────┐┌──────────┐
        │Propostas ││Workflow  ││  Fornec. │
        └─────┬────┘└────┬─────┘└──────────┘
              │          │
              ▼          ▼
         ┌────────┐┌──────────────┐
         │  OCR   ││Ordens Serviço│
         └────────┘└──────────────┘

4. API REST Completa

4.1 Autenticação (/api/auth)

Método Rota Descrição Acesso
POST /api/auth/login Login (email + senha) → JWT Público
POST /api/auth/refresh Renovar token Autenticado
POST /api/auth/logout Invalidar refresh token Autenticado
GET /api/auth/me Dados do usuário logado Autenticado
POST /api/auth/forgot-password Solicitar reset de senha Público
POST /api/auth/reset-password Redefinir senha com token Público

4.2 Usuários (/api/users)

Método Rota Descrição Acesso
GET /api/users Listar usuários (paginado) Admin
GET /api/users/:id Detalhe do usuário Admin
POST /api/users Criar usuário Admin
PATCH /api/users/:id Atualizar usuário Admin
DELETE /api/users/:id Desativar usuário (soft) Admin
GET /api/perfis Listar perfis Admin
POST /api/perfis Criar perfil Admin
PATCH /api/perfis/:id Atualizar permissões Admin

4.3 Locais e Centros de Custo (/api/locais, /api/centros-custo)

Método Rota Descrição Acesso
GET /api/locais Listar locais Autenticado
GET /api/locais/:id Detalhe do local Autenticado
POST /api/locais Criar local Admin, Gestor
PATCH /api/locais/:id Atualizar local Admin, Gestor
DELETE /api/locais/:id Desativar local Admin
GET /api/centros-custo Listar centros de custo Autenticado
GET /api/centros-custo/:id Detalhe Autenticado
POST /api/centros-custo Criar CC Admin
PATCH /api/centros-custo/:id Atualizar CC Admin

4.4 Categorias (/api/categorias)

Método Rota Descrição Acesso
GET /api/categorias Listar (árvore ou flat) Autenticado
GET /api/categorias/:id Detalhe Autenticado
POST /api/categorias Criar categoria Admin
PATCH /api/categorias/:id Atualizar Admin
DELETE /api/categorias/:id Desativar Admin

4.5 Fornecedores (/api/fornecedores)

Método Rota Descrição Acesso
GET /api/fornecedores Listar (paginado, filtros) Autenticado
GET /api/fornecedores/:id Detalhe + certidões Autenticado
POST /api/fornecedores Cadastrar fornecedor Admin, Gestor
PATCH /api/fornecedores/:id Atualizar Admin, Gestor
DELETE /api/fornecedores/:id Desativar Admin
GET /api/fornecedores/:id/certidoes Listar certidões Autenticado
POST /api/fornecedores/:id/certidoes Upload certidão Fornecedor, Admin
PATCH /api/fornecedores/:id/certidoes/:certId Atualizar certidão Admin
GET /api/fornecedores/:id/avaliacoes Histórico de avaliações Autenticado

4.6 Demandas (/api/demandas)

Método Rota Descrição Acesso
GET /api/demandas Listar (paginado, filtros por status/CC/local/categoria) Autenticado
GET /api/demandas/:id Detalhe completo Autenticado
POST /api/demandas Criar demanda (rascunho) Solicitante, Gestor
PATCH /api/demandas/:id Atualizar demanda Solicitante, Gestor
POST /api/demandas/:id/publicar Publicar (rascunho → aberta) Solicitante, Gestor
POST /api/demandas/:id/cancelar Cancelar demanda Gestor, Admin
POST /api/demandas/:id/documentos Upload documento Solicitante, Gestor
DELETE /api/demandas/:id/documentos/:docId Remover documento Solicitante, Gestor
GET /api/demandas/:id/itens-linha Listar itens de linha Autenticado
POST /api/demandas/:id/itens-linha Adicionar item de linha Gestor
PATCH /api/demandas/:id/itens-linha/:itemId Atualizar item Gestor
DELETE /api/demandas/:id/itens-linha/:itemId Remover item Gestor
POST /api/demandas/:id/enviar-cotacao Enviar p/ cotação (validações) Gestor
GET /api/demandas/:id/timeline Timeline de eventos Autenticado

4.7 Propostas (/api/propostas)

Método Rota Descrição Acesso
GET /api/demandas/:demandaId/propostas Listar propostas da demanda Autenticado
GET /api/propostas/:id Detalhe da proposta Autenticado
POST /api/demandas/:demandaId/propostas Upload proposta (PDF) Fornecedor
POST /api/propostas/:id/nova-versao Nova versão do PDF Fornecedor
GET /api/propostas/:id/versoes Listar versões Autenticado
GET /api/propostas/:id/versoes/:versaoId Detalhe da versão + dados OCR Autenticado
POST /api/propostas/:id/selecionar Selecionar proposta vencedora Gestor
PATCH /api/propostas/:id/dados-extraidos Corrigir dados do OCR Gestor
GET /api/demandas/:demandaId/comparativo Painel comparativo Autenticado
POST /api/demandas/:demandaId/comparativo/gerar Gerar/atualizar comparativo Gestor
POST /api/demandas/:demandaId/comparativo/anotacoes Adicionar anotação Autenticado

4.8 Orçamento (/api/orcamento)

Método Rota Descrição Acesso
GET /api/orcamento Listar planejamento (filtros: ano, mês, CC, categoria) Financeiro, Admin
GET /api/orcamento/:id Detalhe Financeiro, Admin
POST /api/orcamento Criar linha orçamentária Admin
PATCH /api/orcamento/:id Atualizar planejado Admin
POST /api/orcamento/importar Importar planilha Admin
GET /api/orcamento/resumo Resumo planejado x comprometido x realizado Financeiro, Diretoria
GET /api/orcamento/verificar Verificar disponibilidade (CC, categoria, valor) Sistema

4.9 Workflow de Aprovação (/api/workflow)

Método Rota Descrição Acesso
POST /api/demandas/:demandaId/workflow/iniciar Iniciar workflow Gestor
GET /api/workflow/:id Status do workflow Autenticado
POST /api/workflow/:id/aprovar Aprovar etapa atual Aprovador da etapa
POST /api/workflow/:id/reprovar Reprovar (com justificativa) Aprovador da etapa
POST /api/workflow/:id/aprovar-com-ressalva Aprovar com ressalva Aprovador da etapa
GET /api/workflow/pendentes Minhas aprovações pendentes Autenticado
GET /api/matriz-alcada Listar regras de alçada Admin
POST /api/matriz-alcada Criar regra Admin
PATCH /api/matriz-alcada/:id Atualizar regra Admin
DELETE /api/matriz-alcada/:id Desativar regra Admin

4.10 Ordens de Serviço (/api/ordens-servico)

Método Rota Descrição Acesso
GET /api/ordens-servico Listar OS Autenticado
GET /api/ordens-servico/:id Detalhe Autenticado
POST /api/ordens-servico/:id/iniciar Marcar início execução Gestor
POST /api/ordens-servico/:id/concluir Marcar conclusão Gestor
POST /api/ordens-servico/:id/cancelar Cancelar OS Admin
POST /api/ordens-servico/:id/avaliacao Avaliar fornecedor Gestor, Solicitante

4.11 Dashboard (/api/dashboard)

Método Rota Descrição Acesso
GET /api/dashboard/indicadores Cards principais Autenticado
GET /api/dashboard/demandas-por-status Gráfico por status Autenticado
GET /api/dashboard/demandas-por-categoria Gráfico por categoria Autenticado
GET /api/dashboard/consumo-orcamento Plan. x Comprom. x Realiz. Financeiro, Diretoria
GET /api/dashboard/propostas-por-fornecedor Gráfico fornecedores Gestor
GET /api/dashboard/alertas Alertas do usuário Autenticado
PATCH /api/dashboard/alertas/:id/ler Marcar alerta como lido Autenticado

4.12 Relatórios (/api/relatorios)

Método Rota Descrição Acesso
GET /api/relatorios/consumo-orcamentario Por CC e categoria Financeiro, Diretoria
GET /api/relatorios/saving Saving gerado Financeiro, Diretoria
GET /api/relatorios/historico-decisoes Trilha de auditoria Admin
GET /api/relatorios/lead-time Lead time por status Gestor, Admin
GET /api/relatorios/gargalos Gargalos de aprovação Admin
GET /api/relatorios/exportar/:tipo Exportar PDF ou Excel Autenticado

4.13 OCR (/api/ocr) — interno

Método Rota Descrição Acesso
POST /api/ocr/extrair Disparar extração de PDF Sistema/Gestor
GET /api/ocr/status/:jobId Status do job de extração Sistema/Gestor

5. Workflow de Aprovação — Máquina de Estados

5.1 Diagrama de Estados da Demanda

                    ┌──────────┐
                    │ RASCUNHO │
                    └────┬─────┘
                         │ publicar (valida: itens_linha, CC, local)
                         ▼
                    ┌──────────┐
                    │  ABERTA  │
                    └────┬─────┘
                         │ gestor assume
                         ▼
                    ┌──────────┐
                    │ EM_ESCOPO│  ← define itens de linha
                    └────┬─────┘
                         │ enviar cotação (valida: ≥1 item)
                         ▼
                    ┌───────────┐
                    │ EM_COTAÇÃO│  ← fornecedores enviam propostas
                    └────┬──────┘
                         │ todas propostas recebidas
                         ▼
                ┌─────────────────┐
                │PROPOSTAS_RECEB. │
                └────────┬────────┘
                         │ gestor inicia comparação
                         ▼
                   ┌─────────────┐
                   │EM_COMPARAÇÃO│  ← painel comparativo, OCR
                   └──────┬──────┘
                          │ seleciona proposta → inicia workflow
                          ▼
                   ┌─────────────┐
                   │EM_APROVAÇÃO │  ← fluxo de alçadas
                   └──────┬──────┘
                     ┌────┼────┐
                     ▼    │    ▼
              ┌──────┐    │  ┌──────────┐
              │REPROV│    │  │APROVADA  │
              └──────┘    │  └────┬─────┘
                          │       │ gera OS automática
                          │       ▼
                          │  ┌──────────┐
                          │  │OS_EMITIDA│
                          │  └────┬─────┘
                          │       │
                          │       ▼
                          │  ┌────────────┐
                          │  │EM_EXECUÇÃO │
                          │  └─────┬──────┘
                          │        │
                          │        ▼
                          │  ┌──────────┐
                          │  │CONCLUÍDA │
                          │  └──────────┘
                          │
            (cancelar em qualquer ponto)
                          ▼
                    ┌──────────┐
                    │CANCELADA │
                    └──────────┘

5.2 Fluxo de Alçadas (Workflow de Aprovação)

Proposta Selecionada (valor R$)
         │
         ▼
┌────────────────────────┐
│ Consultar matriz_alcada│
│ (CC + valor)           │
└────────┬───────────────┘
         │
         ▼
    Valor ≤ alçada do Gestor?
    ├── SIM → Aprovação automática pelo Gestor ──→ APROVADO
    │
    └── NÃO → Fluxo Sequencial:
              │
              ▼
         ┌─────────────────────┐
     (1) │ Gestor de Facilities│──→ Aprova? ──→ Próxima etapa
         └─────────────────────┘       │
                                    Reprova? ──→ REPROVADO
              │
              ▼
         ┌─────────────────────┐
     (2) │ Aprovador Financeiro│──→ Aprova? ──→ Próxima etapa
         └─────────────────────┘       │
                                    Reprova? ──→ REPROVADO
              │
              ▼
         ┌─────────────────────┐
     (3) │ Diretoria           │──→ Aprova? ──→ APROVADO
         └─────────────────────┘       │
                                    Reprova? ──→ REPROVADO

5.3 Exceções Emergenciais

  1. Demanda marcada como criticidade = 'critica' pode ser sinalizada como emergencial
  2. Workflow emergencial exige justificativa_emergencial obrigatória
  3. Permite pular etapas intermediárias, indo direto ao aprovador de maior alçada
  4. Gera alerta automático para todos os aprovadores pulados
  5. Registra em audit_log com flag emergencial = true

5.4 Aprovação com Ressalva

  • Qualquer aprovador pode aprovar com ressalva (aprovado_com_ressalva)
  • Exige campo observacao obrigatório
  • O workflow continua normalmente, mas a OS gerada carrega flag de ressalva
  • Visível no relatório de histórico de decisões

6. OCR/IA — Estratégia de Extração Inteligente

6.1 Pipeline de Processamento

PDF Upload
    │
    ▼
┌──────────────────┐
│ 1. Armazenar S3  │  (MinIO / S3-compatible)
└────────┬─────────┘
         │
         ▼
┌──────────────────┐
│ 2. Fila Bull/    │  (Redis queue: "ocr-extraction")
│    BullMQ        │
└────────┬─────────┘
         │ Worker processa
         ▼
┌──────────────────────────────────────┐
│ 3. Extrair texto do PDF             │
│    - pdf-parse (texto nativo)       │
│    - Tesseract.js (se escaneado)    │
└────────┬─────────────────────────────┘
         │
         ▼
┌──────────────────────────────────────┐
│ 4. Enviar para GPT-4o-mini          │
│    System prompt estruturado:       │
│    - Extrair: valor_bruto,          │
│      valor_liquido, impostos,       │
│      condicao_pagamento,            │
│      prazo_execucao, data_entrega   │
│    - Mapear itens ↔ itens_linha     │
│    - Retornar JSON tipado           │
│    - Indicar confiança (0-100%)     │
└────────┬─────────────────────────────┘
         │
         ▼
┌──────────────────────────────────────┐
│ 5. Salvar em versoes_proposta       │
│    - dados_extraidos (raw GPT)      │
│    - dados_parseados (estruturado)  │
│    - confiabilidade                 │
└────────┬─────────────────────────────┘
         │
         ▼
┌──────────────────────────────────────┐
│ 6. Calcular match_escopo_pct        │
│    Itens mapeados / Total itens     │
└──────────────────────────────────────┘

6.2 System Prompt para GPT-4o-mini

Você é um extrator de dados de propostas comerciais de serviços de Facilities.

Dado o texto de uma proposta PDF, extraia os seguintes campos em JSON:

{
  "valor_bruto": number | null,
  "valor_liquido": number | null,
  "impostos": {
    "iss": number | null,
    "inss": number | null,
    "pcc": number | null,
    "outros": number | null
  },
  "condicao_pagamento": string | null,
  "prazo_execucao_dias": number | null,
  "data_entrega_estimada": string | null,   // ISO 8601
  "itens": [
    {
      "descricao": string,
      "valor_unitario": number | null,
      "quantidade": number | null,
      "valor_total": number | null,
      "unidade": string | null
    }
  ],
  "confianca_geral": number   // 0 a 100
}

Regras:
- Se o campo não for encontrado, retorne null
- Valores monetários em BRL, sem símbolo
- confianca_geral indica % de certeza da extração
- Retorne SOMENTE o JSON, sem explicações

6.3 Match de Escopo

O serviço compara itens retornados pelo GPT com itens_linha da demanda usando similaridade textual (Levenshtein / embeddings simples). Resultado: match_escopo_pct na proposta.

6.4 Tratamento de Falhas

  • Confiabilidade < 60%: alerta ao Gestor para revisão manual
  • PDF escaneado com baixa qualidade: fallback para Tesseract + retry GPT
  • Timeout GPT: retry com backoff exponencial (3 tentativas)
  • Todos os erros logados em audit_log

7. Segurança

7.1 RBAC — Controle de Acesso por Perfil

// Decorator customizado
@Roles('administrador', 'gestor_facilities')
@UseGuards(JwtAuthGuard, RolesGuard)

Matriz de Permissões:

Recurso Solicitante Gestor Financeiro Diretoria Fornecedor Admin
Criar demanda
Definir escopo
Upload proposta
Comparar propostas
Selecionar proposta
Aprovar workflow
Ver orçamento
Editar orçamento
Cadastros base
Relatórios
Avaliar fornecedor

7.2 Autenticação

  • JWT com access token (15 min) + refresh token (7 dias)
  • Refresh tokens armazenados em banco (revogáveis)
  • Bcrypt para hash de senhas (salt rounds: 12)
  • Rate limiting: 5 tentativas de login / 15 min por IP

7.3 LGPD

  • Dados pessoais de fornecedores (CPF/CNPJ) criptografados em repouso (AES-256)
  • Endpoint DELETE /api/users/:id/dados-pessoais para anonimização
  • Consentimento registrado no cadastro de fornecedores
  • Logs de acesso a dados sensíveis em audit_log
  • Retenção de logs: 5 anos (configurável)

7.4 Audit Log

Todo CUD (Create, Update, Delete) é interceptado pelo AuditInterceptor:

@Injectable()
export class AuditInterceptor implements NestInterceptor {
  intercept(context: ExecutionContext, next: CallHandler) {
    const req = context.switchToHttp().getRequest();
    const before = /* snapshot antes */;
    return next.handle().pipe(
      tap(result => {
        this.auditService.log({
          usuario_id: req.user.id,
          acao: req.method,
          entidade: /* extraído da rota */,
          entidade_id: req.params.id,
          dados_antes: before,
          dados_depois: result,
          ip: req.ip,
          user_agent: req.headers['user-agent'],
        });
      }),
    );
  }
}

8. Infraestrutura e Deploy

8.1 Ambientes

Ambiente Descrição
development Local, Docker Compose
staging Pré-produção
production Produção

8.2 Docker Compose (dev)

services:
  api:
    build: ./backend
    ports: ["3000:3000"]
    depends_on: [postgres, redis]
    environment:
      DATABASE_URL: postgresql://hefesto:hefesto@postgres:5432/hefesto
      REDIS_URL: redis://redis:6379
      JWT_SECRET: ${JWT_SECRET}
      OPENAI_API_KEY: ${OPENAI_API_KEY}
      S3_ENDPOINT: http://minio:9000

  frontend:
    build: ./frontend
    ports: ["5173:5173"]

  postgres:
    image: postgres:16-alpine
    volumes: ["pgdata:/var/lib/postgresql/data"]
    environment:
      POSTGRES_DB: hefesto
      POSTGRES_USER: hefesto
      POSTGRES_PASSWORD: hefesto

  redis:
    image: redis:7-alpine

  minio:
    image: minio/minio
    command: server /data --console-address ":9001"
    ports: ["9000:9000", "9001:9001"]

volumes:
  pgdata:

8.3 Tecnologias e Bibliotecas

Camada Tecnologia
Backend NestJS 10+, TypeScript 5+
ORM TypeORM (migrations + entities)
Validação class-validator, class-transformer
Filas BullMQ + Redis
Autenticação @nestjs/passport, passport-jwt
Upload Multer + S3 SDK
PDF parse pdf-parse, Tesseract.js
IA OpenAI SDK (GPT-4o-mini)
Frontend React 18+, Vite 5+
UI Kit shadcn/ui + Tailwind CSS
State TanStack Query (React Query)
Gráficos Recharts
Tabelas TanStack Table
Exportação jsPDF, ExcelJS
Testes Jest (back), Vitest (front)

9. Índices do Banco de Dados

-- Performance queries frequentes
CREATE INDEX idx_demandas_status ON demandas(status);
CREATE INDEX idx_demandas_solicitante ON demandas(solicitante_id);
CREATE INDEX idx_demandas_cc ON demandas(centro_custo_id);
CREATE INDEX idx_demandas_local ON demandas(local_id);
CREATE INDEX idx_demandas_created ON demandas(created_at DESC);

CREATE INDEX idx_propostas_demanda ON propostas(demanda_id);
CREATE INDEX idx_propostas_fornecedor ON propostas(fornecedor_id);

CREATE INDEX idx_workflow_status ON workflow_aprovacao(status);
CREATE INDEX idx_workflow_demanda ON workflow_aprovacao(demanda_id);

CREATE INDEX idx_os_status ON ordens_servico(status);
CREATE INDEX idx_os_fornecedor ON ordens_servico(fornecedor_id);

CREATE INDEX idx_orcamento_periodo ON orcamento_planejado(ano, mes);
CREATE INDEX idx_orcamento_cc ON orcamento_planejado(centro_custo_id);

CREATE INDEX idx_alertas_usuario ON alertas(usuario_id, lido, created_at DESC);

CREATE INDEX idx_certidoes_fornecedor ON certidoes(fornecedor_id);
CREATE INDEX idx_certidoes_validade ON certidoes(data_validade);

CREATE INDEX idx_audit_log_entidade ON audit_log(entidade, entidade_id);
CREATE INDEX idx_audit_log_usuario ON audit_log(usuario_id, created_at DESC);

10. Regras de Negócio Críticas

  1. Demanda sem itens de linha não pode ser publicada — validação no POST /demandas/:id/publicar
  2. Demanda sem CC e Local não pode ser publicada — validação no POST /demandas/:id/publicar
  3. Fornecedor com certidão vencida não pode receber OS — verificação no momento da geração da OS
  4. Alerta automático quando proposta > 20% do orçamento planejado — trigger no OrcamentoService.verificar()
  5. OS gerada automaticamente após aprovação final — event listener no WorkflowService
  6. Rating do fornecedor atualizado após avaliação — média ponderada recalculada
  7. Valor comprometido atualizado ao emitir OSOrcamentoService.comprometer()
  8. Valor realizado atualizado ao concluir OSOrcamentoService.realizar()
  9. Soft delete em todas as entidades cadastrais — campo ativo ao invés de DELETE físico

Documento gerado para o projeto HEFESTO — v1.0