Spec técnica · Stack open source · Pronta para auditoria

Infraestrutura digital de proteção animal — arquitetura completa

Web (Next.js 15) + API REST (NestJS 11) + Mobile (Expo SDK 54) + PostgreSQL 16/PostGIS + Redis. Multi-tenant, RBAC, cadeia SHA-256 e dossiês PDF. Zero licenciamento, deploy via Docker Compose.

18Módulos
159Endpoints
26Modelos
48Páginas
12Perfis RBAC
414Blocos integridade
Visão geral
Acessos & Credenciais
API · 22 módulos
Modelos · Banco
Arquitetura
Integridade SHA-256
Stack
Notificações
Segurança & LGPD
Visão Geral

O que está em pé hoje

Tudo abaixo é mensurado direto no banco PostgreSQL e no log do Nest. Não há mock — são registros reais semeados via prisma/seed.ts e prisma/seed_legal.ts.

10
Usuários
6
ONGs (tenants)
89
Animais
57
Casos
202
Evidências
144
Custódia
38
Dossiês PDF
414
Integrity blocks
81
Doações
30
Prontuários
29
Vacinações
1267
Audit logs

Componentes do sistema

🖥 Web Next.js 15

App Router, Server Components, Turbopack. 42 páginas em 7 portais (público, admin, ong, clínico, jurídico, inteligência, auth). Tailwind 4 com design tokens GDF.

Next.js 15.5React 19Tailwind 4

API NestJS 11

22 controllers, 139 endpoints documentados via Swagger. JWT HS256 + refresh rotativo. Multi-tenant via AsyncLocalStorage. SWC compile sub-segundo.

NestJS 11Prisma 6.19SWC

📱 Mobile Expo SDK 54

App MEL Campo. iOS + Android via Expo Go ou EAS Build, e versão web (Expo Web) bundlada via Metro. WatermelonDB offline-first (nativo) com fallback API (web).

Expo 54RN 0.81React 19

🗄 PostgreSQL 16 + PostGIS

23 modelos Prisma. Indexes compostos (tenantId, status). Geo via PostGIS para lat/long e mapa de calor. 6 migrations aplicadas.

Postgres 16PostGIS 3.4Prisma 6

🔴 Redis 7 + BullMQ

Cache de sessão, rate limiting, filas (geração de PDF, envio de email/WhatsApp). BullMQ workers podem escalar horizontalmente.

Redis 7BullMQ 5

🐳 Docker Compose

Stack completa em docker/docker-compose.yml: postgres + redis + healthchecks. Reproduzível em qualquer ambiente. Pronta para deploy on-premise no datacenter do GDF.

DockerCompose
URLs Públicas + Credenciais

Acessos operacionais

Plataforma completa rodando em produção na infraestrutura Hostinger + Dokploy. URLs fixas, com SSL Let's Encrypt automático, sem dependência de túneis temporários.

5 ambientes públicos

Landing institucional

Apresentação pública do projeto · roadmap, perfis, documentação técnica.

https://info.projetomel.com.br

Site Web (Next.js)

Portal logado · todas as áreas administrativas, jurídicas e públicas.

https://projetomel.com.br

API REST (NestJS)

Backend completo. Auth JWT Bearer. Base path /api/v1.

https://api.projetomel.com.br/api/v1

App MEL Campo (mobile)

Via Expo Go (App Store / Google Play) · canal production.

@phil.antunes/mel-campo

10 usuários de teste · cobre todos os 12 papéis

Email Senha Nome Papel efetivo Onde testar
admin@projetomel.com.br admin123 Administrador MEL Admin Global /credenciais-demo · /tenants · /audit · /whatsapp · /expo
governo@gdf.gov.br senha123 Carlos Lima Operador Tudo do admin exceto remover/criar Admins
gestora@patinhas.org.br senha123 Maria Santos Gestora ONG /patinhas-cerrado/dashboard · doações com saldo + aprovar
voluntario@gmail.com senha123 João Oliveira Voluntário App MEL Campo (mobile/web) · registro de resgates
vet@clinica.com.br senha123 Dra. Ana Pereira Veterinária /patinhas-cerrado/prontuarios · /vacinas · /laudos
promotor@mpdft.mp.br senha123 Dra. Beatriz Costa Promotor MP /evidencias · /custodia · /dossies · /verificacao
policia@pmdf.gov.br senha123 Sgt. Ricardo Alves Polícia Ambiental /dashboard · /mapa · /hotspots
conselho@gdf.gov.br senha123 Fernanda Rocha Conselheira /dashboard cross-tenant (somente leitura)
doador@gmail.com senha123 Pedro Mendes Doador /patinhas-cerrado/doar · transparência pública
luizbueno463@gmail.com Bueno Admin Global 2º admin do sistema

6 ONGs (Tenants)

Patinhas do Cerrado

patinhas-cerrado · CNPJ 12.345.678/0001-01

SOS Animal DF

sos-animal-df · CNPJ 23.456.789/0001-02

Anjos de Patas DF

anjos-de-patas · CNPJ 34.567.890/0001-03

Cerrado Vivo

cerrado-vivo · CNPJ 45.678.901/0001-04

Amigos dos Bichos

amigos-dos-bichos · CNPJ 56.789.012/0001-05

Proteção Animal Brasília

protecao-animal-bsb · CNPJ 67.890.123/0001-06

API REST

22 módulos · 139 endpoints

Cada controller tem auth JWT (exceto endpoints públicos marcados com @Public), guards de RBAC e contexto de tenant injetado via interceptor.

🛡 AdminController /admin

18 endpoints — gestão de tenants, usuários globais, audit log, expo-tunnel dinâmico.

Admin only+Operator

💰 DonationController /donations

10 endpoints — list, stats, balance, approve, reject, applications, webhook MercadoPago.

JWT+Public webhook

LegalController /legal

9 endpoints — evidence, custody, dossier (get + generate + download), verify chain, integrity blocks.

JWT + Tenant

🏠 TenantController /tenants

9 endpoints — CRUD de ONGs, listagem pública, branding, slug routing.

Mixed

🐾 AnimalController /animals

9 endpoints — CRUD com fotos georreferenciadas, histórico clínico, status, status público.

JWT

📋 CaseController /cases

9 endpoints — state machine de 8 estados, transições com hash, timeline.

JWT + Tenant

📈 CouncilController /council

8 endpoints — dashboard cross-tenant da Conselheira, KPIs agregados, leitura pura.

COUNCIL only

👤 UserController /users

8 endpoints — perfil próprio (/me), update, password change.

JWT

🔐 AuthController /auth

8 endpoints — login, register, register-ong, refresh, logout, me.

Mostly public

👥 UserTenantController /user-tenants

7 endpoints — membership N:N usuário↔ONG, aprovação de voluntários.

JWT

📊 TransparencyController /transparency

6 endpoints — stats públicas, timeline mensal, mapa anonimizado, lista de ONGs.

100% público

🩺 MedicalController /medical

6 endpoints — prontuários (22), vacinações (29), histórico imutável.

VETERINARIAN+

🔔 NotificationController /notifications

5 endpoints — list, markAsRead, broadcast. 35 notificações ativas.

JWT

🔌 IntegrationController /integration

5 endpoints — SEPAN report, MercadoPago preference, sync externo.

ADMIN

🏘 FosterHomeController /foster-homes

5 endpoints — lares temporários, capacidade, espécies aceitas. 4 cadastros.

ONG_MANAGER+

📞 WhatsAppController /whatsapp

4 endpoints — Baileys session, QR code, send message.

ADMIN

🗺 GeoController /geo

4 endpoints — heatmap PostGIS, hotspots, regiões administrativas.

JWT

🤝 AdoptionController /adoptions

4 endpoints — triagem, período de teste, finalização. 12 adoções concluídas.

JWT + Tenant

🔄 SyncController /sync

2 endpoints — pull/push para mobile offline (WatermelonDB).

JWT

📁 StorageController /storage

1 endpoint — upload multipart com sharp + path traversal protection.

JWT

HealthController /health

1 endpoint — verifica DB + Redis + retorna timestamps.

Public

📝 AuditController /audit

1 endpoint — list audit logs (filtros por user, action, entity, IP). 28 logs.

ADMIN
Modelo de Dados

23 modelos Prisma · 6 migrations

Schema relacional normalizado em PostgreSQL 16 + PostGIS. Todos os modelos têm tenantId (UUID) para isolamento multi-tenant via interceptor de contexto.

Tenant

ONGs cadastradas. CNPJ, slug único, cor primária, descrição. 6 registros.

User

bcrypt 12 rounds. GlobalRole (ADMIN/OPERATOR/USER). 10 registros.

UserTenant

Membership N:M com TenantRole (9 papéis).

Animal · AnimalPhoto

Foto com EXIF/GPS, hash de integridade. 59 animais.

Case · CaseAnimal

State machine de 8 estados. 48 casos (36 abertos).

CaseTransition · CaseTask

Transições com hash. Tasks atribuídas a usuários.

MedicalRecord

Diagnóstico, tratamento, prescrição. 22 prontuários.

Vaccination

Vacinação com lote, data, próxima dose. 29 registros.

Adoption

Triagem → trial → completed. 12 concluídas.

FosterHome

Lares temporários. Capacidade, espécies. 4 cadastros.

Evidence

fileHash + integrityHash + prevHash. 199 registros.

CustodyRecord

Cadeia de custódia. 144 transferências.

Dossier

PDF gerado por pdfkit. 36 PDFs em disco.

IntegrityBlock

Blockchain lógico SHA-256. 412 blocos.

Donation

PENDING/APPROVED/REJECTED/REFUNDED. 79 doações.

DonationApplication

Prestação de contas (gastos por categoria).

BankAccount

Conta bancária por ONG. PIX, banco, agência.

Notification

In-app, email, WhatsApp, push. 35 ativas.

AuditLog

100% mutações com IP/UA/oldValue/newValue. 28 logs.

RefreshToken

SHA-256 hashed, rotativo, expira em 7d.

Schema do banco — exemplo de query

-- Conta o que está semeado
SELECT
  (SELECT COUNT(*) FROM users)         AS users,        -- 10
  (SELECT COUNT(*) FROM tenants)       AS tenants,      -- 6
  (SELECT COUNT(*) FROM animals)       AS animals,      -- 59
  (SELECT COUNT(*) FROM cases)         AS cases,        -- 48
  (SELECT COUNT(*) FROM evidences)     AS evidences,    -- 199
  (SELECT COUNT(*) FROM custody_records) AS custody,    -- 144
  (SELECT COUNT(*) FROM dossiers)      AS dossiers,     -- 36
  (SELECT COUNT(*) FROM integrity_blocks) AS integrity, -- 412
  (SELECT COUNT(*) FROM donations)     AS donations;    -- 79
Arquitetura

Monolito modular multi-tenant

Arquitetura simples, sem microservices prematuros. Fácil de entender, deployar e auditar. Escalabilidade horizontal via réplicas + Redis cluster + PG read replicas.

Web Next.js
port 3000
Mobile Expo Web
port 8081
Mobile Expo Go
via tunnel
Curl / Postman
qualquer client
↓ HTTPS / JWT Bearer
API NestJS · 22 controllers · 139 endpoints
JWT Auth · RBAC Guard · Tenant Interceptor · Audit Interceptor · Throttler
PostgreSQL 16 + PostGIS
23 modelos · 6 migrations
Redis 7
cache + filas BullMQ
Storage local
jail por tenant

Padrões usados

🔒 Multi-tenant via AsyncLocalStorage

O TenantInterceptor resolve tenantId a partir do header x-tenant-slug ou JWT, e armazena no contexto async. Decorators @TenantId() e @TenantSlug() injetam onde precisar. Queries Prisma sempre filtram por tenantId.

🛡 RBAC declarativo

Decorator @Roles('ADMIN','ONG_MANAGER') em cada handler. RolesGuard verifica o JWT (globalRole) e o tenant context (tenantRole). 403 retornado se não bate.

📝 Audit Log automático

AuditInterceptor captura method+path+oldValue+newValue+IP+userAgent em toda mutação (POST/PUT/PATCH/DELETE) e grava em audit_logs. Não precisa código manual.

⚖ Cadeia de integridade SHA-256

Toda operação legal cria um IntegrityBlock com hash do bloco anterior. Verificação por entityType (Evidence/CustodyRecord/Dossier) detecta adulteração. Ver tab "Integridade".

🔄 Mobile offline-first

App nativo usa WatermelonDB (SQLite) com schema próprio. Sync engine pull/push via POST /sync resolve conflitos last-write-wins por updated_at.

🚦 Rate limiting + Helmet

100 req/60s global por IP via @nestjs/throttler. Helmet com HSTS, CSP, X-Frame-Options, X-Content-Type-Options. CORS configurável por env.

Cadeia de Custódia Digital

Integridade SHA-256 verificável

Replica exatamente o algoritmo do IntegrityService em produção. Cada bloco encadeia ao anterior — adulteração de qualquer byte quebra a verificação.

Fórmula de hash

Implementada em apps/api/src/modules/legal/integrity.service.ts:

function computeHash(
  sequence: number,
  entityType: string,
  entityId: string,
  payload: unknown,
  prevHash: string | null,
  timestamp: Date
): string {
  // Keys do payload são ordenadas alfabeticamente (determinístico)
  const sorted = JSON.stringify(sortObjectKeys(payload));
  const data = [
    String(sequence),
    entityType,
    entityId,
    sorted,
    prevHash ?? '',
    timestamp.toISOString()
  ].join('|');
  return createHash('sha256').update(data).digest('hex');
}

Verificação ao vivo

# 1. Login
TOKEN=$(curl -sX POST "https://api/auth/login" \
  -H "Content-Type: application/json" \
  -d '{"email":"promotor@mpdft.mp.br","password":"senha123"}' \
  | jq -r .accessToken)

# 2. Verificar caso
curl -H "Authorization: Bearer $TOKEN" \
     -H "x-tenant-slug: amigos-dos-bichos" \
     "https://api/legal/cases/0de9a76b.../verify" | jq

# Resposta:
{
  "allValid": true,
  "chains": {
    "evidence": { "valid": true },
    "custody":  { "valid": true },
    "dossier":  { "valid": true }
  },
  "entityVerifications": [
    { "entityId": "e07e9fd5-...", "valid": true, "blockCount": 1 },
    ...
  ]
}

Download de dossiê PDF

# Stream do PDF gerado por pdfkit
curl -H "Authorization: Bearer $TOKEN" \
     -H "x-tenant-slug: amigos-dos-bichos" \
     "https://api/legal/cases/<id>/dossier/download" \
     -o dossie.pdf

# Resposta: application/pdf · 5537 bytes · 2 páginas
# Conteúdo: caso, evidências, custódia, verificação SHA-256
Stack Tecnológica

100% open source · zero royalties

Sem dependência de vendor proprietário. Pronta para deploy on-premise no datacenter do GDF ou em nuvem soberana.

NestJS

v11 · API backend modular

Next.js

v15.5 · App Router + RSC

Expo

SDK 54 · iOS+Android+Web

React

v19.1 · concurrent rendering

React Native

v0.81 · Hermes engine

PostgreSQL

v16 · com PostGIS 3.4

Prisma ORM

v6.19 · 23 modelos

Redis

v7 · cache + filas

BullMQ

v5 · jobs assíncronos

TypeScript

v6 · strict + SWC

Tailwind CSS

v4 · @theme tokens

Lucide Icons

SVG inline open source

Docker Compose

deploy reproduzível

JWT (HS256)

15min + refresh 7d

bcrypt

12 rounds

PDFKit

geração de dossiês

Sharp

processing de imagens

Pino

logs estruturados

Helmet

security headers HTTP

WatermelonDB

SQLite offline mobile

Leaflet

mapas com OSM

Recharts

gráficos React

Baileys

WhatsApp via web

Mercado Pago

PIX + checkout

Comunicação Multicanal

15 templates · 3 canais · totalmente personalizáveis

Toda interação importante na plataforma dispara uma notificação real — email transacional via SMTP, WhatsApp via API oficial e push no aplicativo. Templates versionados em código, prontos para auditoria.

Doador notificado em tempo real, do clique à aplicação

A doadora Mariana recebe duas mensagens reais: a primeira ao confirmar o pagamento, a segunda quando a ONG efetivamente aplica o valor. Mesmo padrão para resgates, casos jurídicos, aprovações de ONG e atribuição de responsável.

Push notification (Expo)

Catálogo completo · 15 gatilhos

Cada card mostra a mensagem real disparada — alterne entre canais.

Segurança & Compliance

Construída para auditoria

Aderência ao arcabouço jurídico brasileiro de proteção de dados, transparência e bem-estar animal. Não é "compliance posterior" — está no DNA da arquitetura.

🔐 Autenticação

  • JWT HS256 · 15min access token
  • Refresh token rotativo 7d (SHA-256 hashed no banco)
  • Senhas com bcrypt 12 rounds (~250ms)
  • Rate limit 100 req / 60s por IP

🛡 RBAC granular

  • 3 papéis globais (ADMIN, OPERATOR, USER)
  • 9 papéis de tenant (ADMIN, ONG_MANAGER, ...)
  • Decorator @Roles() em cada handler
  • OPERATOR não pode tocar em outros ADMINs

📋 Audit Log

  • 100% das mutações registradas
  • IP, user-agent, oldValue, newValue, timestamp
  • 28 logs no banco atualmente
  • Endpoint GET /admin/audit-logs

Integridade jurídica

  • SHA-256 encadeado em Evidence/Custody/Dossier
  • 412 IntegrityBlocks no banco
  • Verificação ao vivo via /legal/.../verify
  • Dossiê PDF com hash incluído

🌐 HTTP Security

  • Helmet (HSTS, CSP, X-Frame-Options)
  • CORS configurável por env
  • Path traversal protection no upload
  • Jail por tenant no storage

📜 LGPD

  • Anonimização nos canais públicos (transparência)
  • Coordenadas GPS arredondadas para ~1km
  • Consentimento explícito no registro
  • Direito ao esquecimento via DELETE /users/me

Aderência legal

Lei 13.709/2018 (LGPD)

Anonimização, audit, consentimento, direito ao esquecimento.

Lei 12.527/2011 (LAI)

Portal de transparência ativa em /transparencia sem login.

Lei 9.605/1998

Cadeia de custódia digital para denúncias ao MP.

Lei 14.064/2020

Apoio à lei de aumento de penas para maus-tratos.

Decreto 10.046/2019

Governança de dados · isolamento multi-tenant.

WCAG 2.1 AA

Contraste 4.5:1 · navegação por teclado · semantic HTML.