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

  1. Todo WHERE em queries Prisma deve incluir empresaId
  2. Acesso cross-tenant retorna 403/404 sem revelar existência do registro
  3. Gestor em modo impersonação: leitura permitida, escrita bloqueada (403)
  4. 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

  1. Cliente faz login via NextAuth (Credentials ou Microsoft OAuth)
  2. Recebe JWT com id, empresaId, gestorId
  3. 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)
  4. 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 = COLABORADORcolaboradorId obrigatório
  • Se tipoDeAtivo = VEICULOveiculoId 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

  1. Nunca expor nomes de tabelas, campos ou stack traces ao frontend
  2. Mensagens amigáveis sempre em português (pt-BR)
  3. Logs detalhados apenas no servidor (console.error)
  4. Frontend exibe mensagens via toast (Sonner) — nunca usar alert()
  5. 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:

  1. Sem token → 401
  2. Token de outro tenant → 403/404
  3. Campos sensíveis no payload (role, empresaId) → ignorados
  4. 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:

  1. Definir model no schema.prisma com CUID, empresaId, ativo, createdAt, updatedAt
  2. Gerar migration aditiva (npx prisma migrate dev --name descricao)
  3. Criar schema Zod em src/lib/validators/{entidade}.schema.ts
  4. Criar service em src/lib/{entidade}Service.ts com CRUD + filtro empresaId
  5. Criar route handler em src/app/api/{entidade}/route.ts
  6. Adicionar testes Vitest (unit + segurança)

Ao modificar uma entidade existente:

  1. Migration aditiva (ADD COLUMN, ALTER COLUMN — nunca DROP)
  2. Atualizar schema Zod correspondente
  3. Atualizar service se necessário
  4. Verificar Omit/Partial nos DTOs que referenciam a entidade
  5. 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.