Documentação Completa — Sistema IGR REURB
Objetivo: Guia de referência para novos desenvolvedores. Contém a visão geral do sistema, arquitetura, todas as entidades, regras de negócio, padrões técnicos e endpoints da API.
1. Visão Geral
O IGR REURB é um ERP Territorial e Jurídico multi-tenant voltado à gestão de projetos de Regularização Fundiária Urbana (Reurb). O sistema transforma dados de geolocalização e cadastros sociais em processos jurídicos robustos, culminando na emissão da CRF (Certidão de Regularização Fundiária) e no registro cartorário.
Stack Tecnológica
| Camada |
Tecnologia |
| Frontend |
Next.js 14 (App Router) + TypeScript + Tailwind CSS |
| Backend |
Next.js Route Handlers (API Routes) |
| ORM |
Prisma Client |
| Banco de Dados |
MySQL |
| Autenticação |
NextAuth.js (JWT) — Credenciais + Microsoft OAuth |
| Validação |
Zod (schemas compartilhados frontend/backend) |
| Testes |
Vitest + fast-check (PBT) |
| Deploy |
Docker (Ubuntu 22) + GitHub Actions |
Princípios Fundamentais
- Mobile First obrigatório
- Multi-tenant com isolamento por
empresaId
- Soft delete via campo
ativo (nunca DELETE físico)
- Migrations aditivas (nunca DROP TABLE/COLUMN em produção)
- Mensagens em pt-BR em toda interface e APIs
- Valores monetários em formato
R$ #.##0,00
2. Arquitetura Multi-tenant
Hierarquia
Gestor (Root)
└── Empresa (Tenant)
├── Projetos
├── Núcleos
├── Lotes
├── Titulares
├── Documentos
├── Cobranças
├── Notificações
└── ... (todas as entidades de negócio)
Tipos de Usuário
| Campo no User |
Tipo |
Acesso |
gestorId preenchido, empresaId nulo |
Gestor |
Visão consolidada de todas as empresas |
empresaId preenchido |
Empresa |
Acesso restrito ao tenant |
gestorId + municipioId |
Prefeitura |
Visão do gestor, sem acesso a empresas |
| Ambos nulos |
Sem vínculo |
Sem acesso a dados de negócio |
Regras de Isolamento
- Todo WHERE em queries Prisma deve incluir
empresaId
- Acesso cross-tenant retorna 403/404 sem revelar existência do registro
- Gestor em modo impersonação: leitura permitida, escrita bloqueada (403)
- Se
gestorId e empresaId ambos preenchidos → trata como Empresa
3. Diagrama de Camadas
┌─────────────────────────────────────────────────┐
│ Frontend (Next.js App Router) │
│ ├── Componentes React │
│ ├── Formulários + Zod │
│ └── fetchApi (HTTP Client) │
├─────────────────────────────────────────────────┤
│ API Layer (Route Handlers) │
│ ├── /api/{entidade}/route.ts │
│ ├── AuthGuard + Tenant Context │
│ └── Swagger/OpenAPI Docs │
├─────────────────────────────────────────────────┤
│ Service Layer (Business Logic) │
│ ├── src/lib/{entidade}Service.ts (domínio) │
│ ├── src/services/{entidade}Service.ts (aux) │
│ └── auditService │
├─────────────────────────────────────────────────┤
│ Data Layer │
│ ├── Prisma Client │
│ └── MySQL │
├─────────────────────────────────────────────────┤
│ Shared │
│ ├── src/lib/validators/*.schema.ts │
│ └── src/lib/utils (dateUtils, csvBuilder...) │
└─────────────────────────────────────────────────┘
Fluxo de Autenticação
- Cliente faz login via NextAuth (Credentials ou Microsoft OAuth)
- Recebe JWT com
id, empresaId, gestorId
- Cada requisição passa pelo AuthGuard que:
- Valida o token
- Resolve o
TenantContext (tipo de usuário)
- Extrai
empresaId efetivo (direto ou via impersonação)
- Service recebe
empresaId e filtra todas as queries
4. Mapa de Entidades (Banco de Dados)
4.1 Módulo: Gestão e Multi-tenant
| Entidade |
PK |
Tenant |
Campos Principais |
gestor |
CUID |
— (root) |
nome, cnpj (unique), email, telefone, logo |
empresa |
CUID |
gestorId |
nome, cnpj (unique), email, telefone, logo |
user |
CUID |
gestorId? / empresaId? |
displayName, email (unique), password, groupId, municipioId |
group |
autoincrement |
— |
name (unique), description, isDefault |
groupPermission |
autoincrement |
groupId |
key (string), allowed (boolean) |
account |
CUID |
userId (cascade) |
OAuth accounts (providerAccountId) |
session |
CUID |
userId (cascade) |
sessionToken, expires |
4.2 Módulo: Estrutura Territorial
| Entidade |
PK |
Tenant |
Relações |
projeto |
CUID |
empresaId |
→ empresa, municipio?, cidade? |
nucleo |
CUID |
empresaId |
→ empresa, projeto, municipio?, cidade?, cartorio? |
lote |
CUID |
empresaId |
→ empresa, nucleo |
edificacao |
CUID |
empresaId |
→ empresa, lote (cascade on delete) |
gleba |
CUID |
empresaId |
→ empresa, projeto |
nucleoConjunto |
autoincrement |
nucleoId |
Agrupamentos de núcleos |
nucleoKml |
autoincrement |
nucleoId |
Arquivos KML de núcleo |
Hierarquia: Projeto → Núcleo → Lote → Edificação
Lote contém:
- Enums geomorfológicos:
SituacaoQuadra, Localizacao, Pedologia, Topografia, Testada, Posicao
- Infraestrutura (strings): esgotamento, agua, energia, lixo, iluminacao, calcamento, passeio, drenagem, muro, acesso
- Dados topográficos: memorialDescritivo, coordenadas (GeoJSON), confrontantes
4.3 Módulo: Estrutura Socioeconômica
| Entidade |
PK |
Tenant |
Relações |
titular |
CUID |
empresaId |
→ empresa, socioMajoritario? (auto-ref PJ→PF) |
conjuge |
CUID |
empresaId |
→ empresa, titular (1:1, cascade) |
dependente |
CUID |
empresaId |
→ empresa, titular (N:1, cascade) |
contatoTitular |
CUID |
empresaId |
→ empresa, titular (cascade) |
loteTitular |
CUID |
empresaId |
→ empresa, lote (cascade), titular, conjuge? |
Titular suporta:
- Pessoa Física: CPF (único por empresa), RG, nome, data nascimento, gênero, filiação, escolaridade, profissão, estado civil, endereço, renda
- Pessoa Jurídica: CNPJ (único por empresa), razão social, nome fantasia, sócio majoritário (auto-referência a PF)
Regras de estado civil:
- Permite cônjuge: CASADO_PARCIAL, CASADO_TOTAL, CASADO_SEPARACAO, UNIAO_ESTAVEL
- Bloqueia cônjuge: SOLTEIRO, DIVORCIADO, VIUVO, SEPARADO
4.4 Módulo: Fluxo Jurídico e Pipeline
| Entidade |
PK |
Tenant |
Descrição |
processoAdministrativo |
CUID |
empresaId |
Vínculo legal Lote ↔ Titular; contém CRF |
statusLote |
CUID |
empresaId |
Tabela customizável (máx 30 ativos/empresa) |
faseWorkflow |
CUID |
empresaId |
Fases visuais do workflow, cores hex |
cronogramaEtapa |
CUID |
empresaId |
Etapas do cronograma por lote (FIXA/CUSTOMIZADA) |
Máquina de estados do ProcessoAdministrativo:
ABERTO → EM_ANALISE → APROVADO
→ REPROVADO → EM_ANALISE
→ ARQUIVADO → EM_ANALISE
StatusLote e FaseWorkflow:
slug e ordem são únicos por empresa
- Limite de 30 registros ativos por empresa em StatusLote
4.5 Módulo: Financeiro
| Entidade |
PK |
Tenant |
Campos Monetários |
cobranca |
CUID |
empresaId |
valor Decimal(10,2), valorPago Decimal(10,2) |
comissao |
CUID |
empresaId |
valor Decimal(10,2), percentual Decimal(5,2) |
Enums:
StatusCobranca: PENDENTE, PAGO, VENCIDO, CANCELADO
StatusComissao: PENDENTE, PAGO, CANCELADO
FormaPagamento: BOLETO, PIX, CARTAO, DINHEIRO, TRANSFERENCIA
Regras de imutabilidade:
- Cobrança com status PAGO ou CANCELADO → não pode alterar valor, dataVencimento, formaPagamento
- Comissão com status PAGO ou CANCELADO → não pode alterar valor, percentual
4.6 Módulo: Notificações
| Entidade |
PK |
Tenant |
Descrição |
notificacao |
CUID |
empresaId |
Editais e notificações vinculados a lote/núcleo |
notificacaoDestinatario |
CUID |
empresaId |
Destinatários com controle de ciência |
Máquina de estados da Notificação:
RASCUNHO → PUBLICADO → PRAZO_ENCERRADO → CONCLUIDO
→ IMPUGNADO → CONCLUIDO
Regras:
- Publicação exige
dataPublicacao e dataLimiteImpugnacao (limite > publicação)
- Impugnação (
impugnou = true) exige dataCiencia preenchida
- Tipos: EDITAL, NOTIFICACAO_PESSOAL, NOTIFICACAO_POSTAL
- Destinatários: CONFRONTANTE, TERCEIRO_INTERESSADO, PROPRIETARIO_REGISTRAL
4.7 Módulo: Documentos (FK Polimórfica)
| Entidade |
PK |
Tenant |
documento |
CUID |
empresaId |
FK polimórfica — exatamente UM campo preenchido por registro:
titularId, loteId, municipioId, cidadeId, conjugeId, dependenteId, nucleoId
CategoriaDocumento (24 valores):
FOTO, CPF, RG, CONTRATO, CROQUI, IPTU, PROCURACAO, CERTIDAO, PLANTA, MEMORIAL, OUTRO, COMPROVANTE_ENDERECO, COMPROVANTE_RENDA, CERTIDAO_NASCIMENTO, CERTIDAO_CASAMENTO, CERTIDAO_DIVORCIO, CERTIDAO_OBITO, ASSINATURA, DECLARACAO, CNH, COMPROVANTE_AQUISICAO_AREA, FOTO_FRENTE, FOTO_LATERAL_ESQUERDA, FOTO_LATERAL_DIREITA, OUTROS_LOTE
Metadados: nome original (255 chars), caminho storage (500 chars), tipo MIME, tamanho (máx 100MB)
4.8 Módulo: Institucional
| Entidade |
PK |
Tenant |
Observação |
municipio |
CUID |
empresaId |
CNPJ 14 dígitos obrigatório, dados de Reurb |
cartorio |
CUID |
empresaId |
CNPJ 14 dígitos opcional |
cidade |
autoincrement |
— (global) |
Tabela de referência legada |
4.9 Módulo: Agenda e Logística
| Entidade |
PK |
Tenant |
Observação |
agendaEvento |
autoincrement |
— (legado) |
tipoDeAtivo: COLABORADOR ou VEICULO |
colaborador |
autoincrement |
— |
Disponibilidade por dia (flags booleanas) |
veiculo |
autoincrement |
— |
placa unique, formato brasileiro |
veiculoocupantes |
autoincrement |
— |
Junção veículo ↔ colaborador |
Regras:
- Se
tipoDeAtivo = COLABORADOR → colaboradorId obrigatório
- Se
tipoDeAtivo = VEICULO → veiculoId obrigatório
dataFim não pode ser anterior a dataInicio
4.10 Módulo: Workflow e Fluxograma
| Entidade |
PK |
Relações |
macroprocesso |
autoincrement |
→ projeto |
microtarefa |
autoincrement |
→ macroprocesso (cascade on delete) |
kpi |
autoincrement |
→ macroprocesso (cascade on delete) |
fluxogramaGerado |
autoincrement |
→ nucleo, cidade |
fluxogramaFase |
autoincrement |
→ fluxogramaGerado (cascade on delete) |
workflow_task |
autoincrement |
Standalone (importação Excel) |
estatistica |
autoincrement |
Contadores de macroprocessos |
Cascades: Remover macroprocesso remove microtarefas+KPIs. Remover fluxograma remove fases.
4.11 Módulo: Segurança e Auditoria
| Entidade |
PK |
Descrição |
auditLog |
CUID |
Trilha imutável de auditoria (sem updatedAt) |
linkCadastro |
CUID |
Token UUID unique para auto-cadastro público |
AuditLog registra:
action: CREATE, UPDATE, DELETE, REACTIVATE
entity: nome da entidade afetada
entityId: ID do registro
changes: JSON com diff (campo anterior → novo)
ipAddress: IPv4/IPv6 (max 45 chars)
userEmail, userId, empresaId
LinkCadastro:
- Token UUID único, indexado
- Uso único (
utilizado = true após consumo)
- Link inativo ou utilizado → acesso negado
5. Enums do Sistema
| Enum |
Valores |
TipoPessoa |
FISICA, JURIDICA |
Genero |
FEMININO, MASCULINO, OUTRO, NAO_INFORMADO |
Nacionalidade |
BRASILEIRO, NATURALIZADO, ESTRANGEIRO |
Escolaridade |
ANALFABETO, FUNDAMENTAL_INCOMPLETO/COMPLETO, MEDIO_INCOMPLETO/COMPLETO, SUPERIOR_INCOMPLETO/COMPLETO, POS_GRADUACAO |
SituacaoProfissional |
ASSALARIADO, AUTONOMO, TRABALHADOR_RURAL, APOSENTADO, SERVIDOR_PUBLICO, DESEMPREGADO, OUTRO |
StatusRenda |
COMPROVADA, NAO_COMPROVADA, AUSENTE |
EstadoCivil |
SOLTEIRO, CASADO_PARCIAL, CASADO_TOTAL, CASADO_SEPARACAO, DIVORCIADO, VIUVO, SEPARADO, UNIAO_ESTAVEL |
OrgaoEmissor |
DPF, DET, DRT, DGPC, IFP, MTE, PC, PM, SJ, SJSP, SPTC, SSP, SEJSP, SESP |
TipoContato |
TELEFONE, EMAIL |
InstrumentoJuridico |
LEGITIMACAO_FUNDIARIA, LEGITIMACAO_POSSE, USUCAPIAO, CONCESSAO_USO, CONCESSAO_DIREITO_REAL, DOACAO |
StatusProcesso |
ABERTO, EM_ANALISE, APROVADO, REPROVADO, ARQUIVADO |
StatusCobranca |
PENDENTE, PAGO, VENCIDO, CANCELADO |
StatusComissao |
PENDENTE, PAGO, CANCELADO |
FormaPagamento |
BOLETO, PIX, CARTAO, DINHEIRO, TRANSFERENCIA |
TipoNotificacao |
EDITAL, NOTIFICACAO_PESSOAL, NOTIFICACAO_POSTAL |
StatusNotificacao |
RASCUNHO, PUBLICADO, PRAZO_ENCERRADO, IMPUGNADO, CONCLUIDO |
TipoDestinatario |
CONFRONTANTE, TERCEIRO_INTERESSADO, PROPRIETARIO_REGISTRAL |
CategoriaDocumento |
24 valores (ver seção 4.7) |
GrauParentesco |
FILHO, ENTEADO, MENOR_TUTELADO, NETO, SOBRINHO, IRMAO, PAI_MAE, AVO, OUTRO |
SituacaoQuadra |
(enum geomorfológico do Lote) |
Localizacao |
(enum geomorfológico do Lote) |
Pedologia |
(enum geomorfológico do Lote) |
Topografia |
(enum geomorfológico do Lote) |
Testada |
(enum geomorfológico do Lote) |
Posicao |
(enum geomorfológico do Lote) |
TipologiaEdificacao |
(enum da Edificação) |
ClassificacaoEdificacao |
(enum da Edificação) |
CondicaoEdificacao |
(enum da Edificação) |
TipoConstrucao |
(enum da Edificação) |
TipoDeAtivo |
COLABORADOR, VEICULO |
6. Diagrama de Relacionamentos
GESTOR 1───N EMPRESA
EMPRESA 1───N PROJETO
EMPRESA 1───N TITULAR
EMPRESA 1───N LOTE
EMPRESA 1───N NOTIFICACAO
EMPRESA 1───N COBRANCA
EMPRESA 1───N DOCUMENTO
PROJETO 1───N NUCLEO
PROJETO 1───N GLEBA
PROJETO 1───N MACROPROCESSO
NUCLEO 1───N LOTE
NUCLEO 1───N NOTIFICACAO (opcional)
LOTE 1───N EDIFICACAO (cascade)
LOTE 1───N LOTETITULAR
LOTE 1───N CRONOGRAMA_ETAPA
LOTE 1───N COBRANCA (opcional)
LOTE 1───N PROCESSO_ADMINISTRATIVO
TITULAR 1───1 CONJUGE (cascade)
TITULAR 1───N DEPENDENTE (cascade)
TITULAR 1───N CONTATO_TITULAR (cascade)
TITULAR 1───N LOTETITULAR
TITULAR 1───N PROCESSO_ADMINISTRATIVO
MACROPROCESSO 1───N MICROTAREFA (cascade)
MACROPROCESSO 1───N KPI (cascade)
FLUXOGRAMA_GERADO 1───N FLUXOGRAMA_FASE (cascade)
NOTIFICACAO 1───N NOTIFICACAO_DESTINATARIO (cascade)
COBRANCA 1───N COMISSAO (opcional)
7. Organização do Código
Estrutura de Diretórios
src/
├── app/ # Next.js App Router
│ ├── api/ # Route Handlers (API)
│ │ ├── agenda/
│ │ ├── cartorios/
│ │ ├── cidades/
│ │ ├── colaboradores/
│ │ ├── cronograma/
│ │ ├── documentos/
│ │ ├── export/
│ │ ├── fases-workflow/
│ │ ├── financeiro/
│ │ ├── fluxogramas/
│ │ ├── gestor/ # APIs do painel Gestor
│ │ ├── grupos/
│ │ ├── lotes/
│ │ ├── macroprocessos/
│ │ ├── me/
│ │ ├── microsoft/ # Integração Microsoft (x-api-key)
│ │ ├── municipios/
│ │ ├── notificacoes/
│ │ ├── nucleos/
│ │ ├── relatorios/
│ │ ├── status-lotes/
│ │ ├── titulares/
│ │ └── usuarios/
│ └── (pages)/ # Páginas do frontend
├── lib/ # Serviços de domínio + utilitários
│ ├── authGuard.ts # AuthGuard central
│ ├── auditService.ts
│ ├── {entidade}Service.ts # Um service por entidade
│ ├── validators/ # Schemas Zod por entidade
│ │ └── {entidade}.schema.ts
│ └── utils/ # Utilitários (dateUtils, csvBuilder, etc)
├── services/ # Serviços auxiliares
│ ├── conjugeService.ts
│ ├── dependenteService.ts
│ └── familiaService.ts
└── tests/
├── properties/ # Property-based tests (fast-check)
└── security/ # Testes de bypass
Serviços de Domínio (src/lib/)
Nomenclatura: {entidade}Service.ts (camelCase)
| Service |
Entidade |
acompanhamentoService |
Acompanhamento do gestor |
auditService |
AuditLog |
cartorioService |
Cartório |
cidadeService |
Cidade |
colaboradorService |
Colaborador |
contatoTitularService |
ContatoTitular |
cronogramaService |
CronogramaEtapa |
documentoService |
Documento |
edificacaoService |
Edificação |
empresaService |
Empresa |
exportService |
Exportação CSV/Excel |
faseWorkflowService |
FaseWorkflow |
financeiroService |
Cobrança + Comissão |
fluxogramaService |
FluxogramaGerado + Fases |
gestorService |
Gestor |
groupService |
Group + Permissions |
loteService |
Lote |
loteTitularService |
LoteTitular |
macroprocessoService |
Macroprocesso + Microtarefas + KPIs |
municipioService |
Município |
notificacaoService |
Notificação + Destinatários |
nucleoService |
Núcleo |
projetoService |
Projeto |
relatorioService |
Relatórios |
statusLoteService |
StatusLote |
titularService |
Titular |
Utilitários (src/lib/)
| Arquivo |
Função |
fetchApi |
HTTP client para comunicação frontend → backend |
prisma |
Instância do Prisma Client |
dateUtils |
Formatação e manipulação de datas |
csvBuilder |
Construção de arquivos CSV |
loteFormatters |
Formatadores específicos de lote |
utils |
Funções utilitárias gerais |
ragCalculator |
Cálculos de RAG (indicadores) |
pirf-docx-generator |
Gerador de relatórios PIRF em DOCX |
pirf-pdf-generator |
Gerador de relatórios PIRF em PDF |
8. Padrões de Código
AuthGuard (src/lib/authGuard.ts)
interface TenantContext {
type: 'gestor' | 'empresa' | 'prefeitura' | 'sem_vinculo';
gestorId?: string;
empresaId?: string;
municipioId?: string;
cidadeId?: number;
userId: string;
}
// Funções exportadas:
getTenantContext(): Promise<TenantContext | null>
getEmpresaIdFromSession(): Promise<string | null>
getGestorIdFromSession(): Promise<string | null>
getEffectiveEmpresaId(request, context): Promise<string | null>
blockWriteDuringImpersonation(request, context): NextResponse | null
unauthorizedResponse(): NextResponse
forbiddenResponse(message?: string): NextResponse
Padrão de Service
interface ServicePattern<T> {
listar(empresaId: string, filtros?: FiltrosPaginacao): Promise<PaginatedResult<T>>
buscarPorId(id: string, empresaId: string): Promise<T | null>
criar(data: CreateDTO, empresaId: string): Promise<T>
atualizar(id: string, data: UpdateDTO, empresaId: string): Promise<T>
inativar(id: string, empresaId: string): Promise<T> // soft delete
reativar(id: string, empresaId: string): Promise<T>
}
Padrão de Route Handler
export async function GET(request: NextRequest) {
const context = await getTenantContext();
if (!context) return unauthorizedResponse();
const empresaId = await getEffectiveEmpresaId(request, context);
if (!empresaId) return forbiddenResponse();
const params = listQuerySchema.safeParse(searchParams);
if (!params.success) return NextResponse.json({ error: params.error }, { status: 400 });
const resultado = await entidadeService.listar(empresaId, params.data);
return NextResponse.json(resultado);
}
Padrão de Validador Zod
// src/lib/validators/{entidade}.schema.ts
import { z } from 'zod';
export const entidadeCreateSchema = z.object({
nome: z.string().min(1).max(200).transform(v => v.trim()),
// ... campos
});
export const entidadeUpdateSchema = entidadeCreateSchema.partial();
export type EntidadeCreateDTO = z.infer<typeof entidadeCreateSchema>;
export type EntidadeUpdateDTO = z.infer<typeof entidadeUpdateSchema>;
9. Endpoints da API
APIs Protegidas por JWT (filtro empresaId obrigatório)
| Grupo |
Base Path |
Operações |
| Agenda |
/api/agenda |
CRUD eventos |
| Cartórios |
/api/cartorios |
CRUD |
| Cidades |
/api/cidades |
CRUD (tabela global) |
| Colaboradores |
/api/colaboradores |
CRUD |
| Cronograma |
/api/cronograma |
CRUD etapas |
| Documentos |
/api/documentos |
CRUD + upload |
| Exportação |
/api/export |
lotes, nucleos, titulares (CSV/Excel) |
| Fases Workflow |
/api/fases-workflow |
CRUD |
| Financeiro |
/api/financeiro |
cobranças, comissões |
| Fluxogramas |
/api/fluxogramas |
CRUD + fases |
| Grupos |
/api/grupos |
CRUD + permissões |
| Lotes |
/api/lotes |
CRUD |
| Macroprocessos |
/api/macroprocessos |
CRUD + microtarefas + KPIs |
| Me |
/api/me |
Dados do usuário logado |
| Municípios |
/api/municipios |
CRUD |
| Notificações |
/api/notificacoes |
CRUD + destinatários |
| Núcleos |
/api/nucleos |
CRUD |
| Relatórios |
/api/relatorios |
Geração de relatórios |
| Status Lotes |
/api/status-lotes |
CRUD (máx 30) |
| Titulares |
/api/titulares |
CRUD PF/PJ + cônjuge + dependentes |
| Usuários |
/api/usuarios |
CRUD |
APIs do Painel Gestor (JWT + gestorId)
| Endpoint |
Descrição |
/api/gestor/acompanhamento |
Visão consolidada |
/api/gestor/dashboard |
Dashboard do gestor |
/api/gestor/empresas |
Gerenciar empresas |
/api/gestor/municipios |
Municípios do gestor |
/api/gestor/perfil |
Perfil do gestor |
/api/gestor/relatorios |
Relatórios consolidados |
APIs de Integração Microsoft (header x-api-key)
| Endpoint |
Descrição |
/api/microsoft/auth |
Autenticação MS |
/api/microsoft/chats |
Chats Teams |
/api/microsoft/groups |
Grupos AD |
/api/microsoft/plans |
Planner |
/api/microsoft/tasks |
Tasks |
/api/microsoft/users |
Usuários AD |
APIs Públicas (sem autenticação)
| Endpoint |
Descrição |
/api/titulares/public-form/[token] |
GET — busca dados do link |
/api/titulares/public-register |
POST — submissão do cadastro |
/api-docs |
Swagger UI interativa |
/api/swagger |
JSON OpenAPI |
APIs de Arquivos Estáticos (JWT)
| Endpoint |
Descrição |
/api/serve-daily |
Imagens diárias |
/api/serve-kml |
Arquivos KML |
/api/serve-tiles |
Tiles de mapa |
10. Tratamento de Erros
Padrão de Respostas HTTP
| Status |
Cenário |
Mensagem |
| 400 |
Validação Zod falhou |
Detalhes campo-a-campo |
| 401 |
Token JWT ausente/expirado |
"Não autenticado. Faça login para continuar." |
| 403 |
Acesso cross-tenant / Impersonação escrita |
"Acesso negado. Você não tem permissão para acessar este recurso." |
| 404 |
Registro não encontrado (ou de outro tenant) |
"Registro não encontrado." |
| 409 |
Violação de unicidade (slug, ordem, CPF) |
"Já existe um registro com esse [campo]." |
| 422 |
Regra de negócio violada |
Mensagem específica da regra |
| 500 |
Erro interno |
"Erro interno do servidor. Tente novamente mais tarde." |
Regras
- Nunca expor nomes de tabelas, campos ou stack traces ao frontend
- Mensagens amigáveis sempre em português (pt-BR)
- Logs detalhados apenas no servidor (console.error)
- Frontend exibe mensagens via toast (Sonner) — nunca usar
alert()
- Auditoria de falhas não quebra a operação principal (try/catch)
11. Regras de Segurança
Autenticação
- NextAuth com JWT (Credentials + Microsoft OAuth)
- Expiração configurável via variável de ambiente
- Rotas não-públicas retornam 401 sem token válido
Proteção Multi-tenant
- Todo WHERE inclui
empresaId
- UPDATE/DELETE valida propriedade do registro
- Acesso cross-tenant → 403/404 sem revelar existência
Impersonação (Gestor → Empresa)
- Via cookie
impersonateEmpresaId ou header x-impersonate-empresa
- Valida que empresa pertence ao gestor
- GET permitido, POST/PATCH/DELETE bloqueado (403)
Integração Microsoft
- Protegida por header
x-api-key = variável MICROSOFT_API_KEY
- Sem token válido → 401
Sanitização
- Validação Zod no frontend E backend (mesmo schema)
trim(), toLowerCase() para emails, replace(/\D/g, "") para dígitos
- Nunca usar
dangerouslySetInnerHTML sem sanitizador
- Headers de segurança (CSP, HSTS, X-Content-Type-Options)
Testes de Segurança Obrigatórios
Para cada nova rota:
- Sem token → 401
- Token de outro tenant → 403/404
- Campos sensíveis no payload (role, empresaId) → ignorados
- Payload malicioso (scripts, SQL) → rejeitado pelo Zod
12. Padrões Técnicos Transversais
| Padrão |
Implementação |
| IDs |
CUID (@id @default(cuid())) para entidades novas; autoincrement para legadas |
| Soft Delete |
Campo ativo Boolean @default(true) — nunca DELETE físico |
| Timestamps |
createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt |
| Multi-tenant |
empresaId String + @@index([empresaId]) em toda entidade de negócio |
| Valores monetários |
Decimal @db.Decimal(10, 2) — formato R$ #.##0,00 no frontend |
| Áreas |
Decimal @db.Decimal(12, 4) |
| Porcentagens |
Decimal @db.Decimal(5, 2) — range [0.00, 100.00] |
| Enums |
Prisma enums para domínios finitos |
| Validação |
Zod com schema único por entidade (frontend + backend) |
| Migrations |
Exclusivamente aditivas — proibido DROP TABLE/COLUMN em produção |
13. Diretrizes para o Novo Desenvolvedor
Ao criar uma nova entidade:
- Definir model no
schema.prisma com CUID, empresaId, ativo, createdAt, updatedAt
- Gerar migration aditiva (
npx prisma migrate dev --name descricao)
- Criar schema Zod em
src/lib/validators/{entidade}.schema.ts
- Criar service em
src/lib/{entidade}Service.ts com CRUD + filtro empresaId
- Criar route handler em
src/app/api/{entidade}/route.ts
- Adicionar testes Vitest (unit + segurança)
Ao modificar uma entidade existente:
- Migration aditiva (ADD COLUMN, ALTER COLUMN — nunca DROP)
- Atualizar schema Zod correspondente
- Atualizar service se necessário
- Verificar Omit/Partial nos DTOs que referenciam a entidade
- Rodar testes
Regras de ouro:
- Todo WHERE inclui
empresaId
- Nunca usar
prisma.$queryRaw com strings dinâmicas
- Soft delete sempre (campo
ativo)
- Toast (Sonner) para mensagens — nunca
alert()
- Mobile first em toda UI
- Formato monetário pt-BR com máscara em campos de valor
- Datas no formato dd/mm/yyyy
- Tabelas com paginação (primeiro, anterior, nro página, próximo, último)
- Tabelas reordenáveis ao clicar no título da coluna
- Listas com filtro ativo/inativo/todos (padrão: Ativos)
- Ações inline em tabelas: Editar (Pencil), Inativar (Ban), Reativar (Play)
14. Variáveis de Ambiente
⚠️ Nunca comitar valores reais. Preencher localmente.
| Variável |
Descrição |
DATABASE_URL |
Connection string MySQL |
NEXTAUTH_SECRET |
Secret para JWT |
NEXTAUTH_URL |
URL base da aplicação |
MICROSOFT_API_KEY |
Chave para integração Microsoft |
15. Comandos Úteis
# Instalar dependências
npm install
# Rodar em desenvolvimento
npm run dev
# Gerar Prisma Client
npx prisma generate
# Criar migration
npx prisma migrate dev --name descricao_da_alteracao
# Rodar testes
npx vitest --run
# Build
npm run build
# Docker (produção)
docker compose up -d
Documento gerado em 30/06/2026 — Referência completa do sistema IGR REURB para onboarding de desenvolvedores.