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
167Endpoints
26Modelos
50Páginas
12Perfis RBAC
412Blocos integridade
Visão geral
Acessos & Credenciais
API · 167 endpoints
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.

16
Usuários
6
ONGs (tenants)
93
Animais
52
Casos
203
Evidências
144
Custódia
52
Dossiês PDF
412
Integrity blocks
79
Doações
30
Prontuários
29
Vacinações
3.300+
Audit logs

Componentes do sistema

🖥 Web Next.js 15

App Router, Server Components, Turbopack. 50 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

23 controllers, 167 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

26 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://projetomel.com.br/sobre

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

Documentacao interativa da API

A API possui documentacao auto-gerada via Swagger/OpenAPI. Explore endpoints, teste requests e veja schemas diretamente no navegador.

🌐 Portal API Landing page da API com links /api Swagger UI Interface interativa · Try it out /api/docs/ 📖 Redoc Referencia completa · schemas /api/reference/

Perfis de acesso · 16 usuários cobrem todos os 12 papéis

Papel efetivo Onde atua
Admin Global /tenants · /audit · /whatsapp · /expo
Operador Tudo do admin exceto remover/criar Admins
Gestora ONG /patinhas-cerrado/dashboard · doações com saldo + aprovar
Voluntário App MEL Campo (mobile/web) · registro de resgates
Veterinária /patinhas-cerrado/prontuarios · /vacinas · /laudos
Promotor MP /evidencias · /custodia · /dossies · /verificacao
Polícia Ambiental /dashboard · /mapa · /hotspots
Conselheira /dashboard cross-tenant (somente leitura)
Doador /patinhas-cerrado/doar · transparência pública

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

23 controllers · 167 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

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

Admin only+Operator

🏠 TenantController /tenants

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

Mixed

💰 DonationController /donations

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

JWT+Public webhook

📋 CaseController /cases

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

JWT + Tenant

LegalController /legal

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

JWT + Tenant

🐾 AnimalController /animals

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

JWT

🔐 AuthController /auth

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

Mostly public

📈 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

🩺 MedicalController /medical

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

VETERINARIAN+

📊 TransparencyController /transparency

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

100% público

👥 UserTenantController /tenants/:id/members

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

JWT

🏘 FosterHomeController /foster-homes

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

ONG_MANAGER+

🔔 NotificationController /notifications

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

JWT

🧾 DonationCategoryController /donation-categories

4 endpoints — categorias de aplicação de doações (prestação de contas).

ONG_MANAGER+

🔌 IntegrationController /integration

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

ADMIN

📞 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. 9 adoções concluídas.

JWT + Tenant

🔄 SyncController /sync

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

JWT

📝 AuditController /audit-logs

2 endpoints — list audit logs (filtros por user, action, entity, IP). 3.300+ logs.

ADMIN

📁 StorageController /storage

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

JWT

HealthController /health

1 endpoint — verifica DB + Redis + retorna timestamps.

Public
Modelo de Dados

26 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). 16 registros.

UserTenant

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

Animal · AnimalPhoto

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

Case · CaseAnimal

State machine de 8 estados. 52 casos.

CaseTransition · CaseTask

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

MedicalRecord

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

Vaccination

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

Adoption

Triagem → trial → completed. 9 concluídas.

FosterHome

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

Evidence

fileHash + integrityHash + prevHash. 203 registros.

CustodyRecord

Cadeia de custódia. 144 transferências.

Dossier

PDF gerado por pdfkit. 52 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. 3.300+ 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,        -- 16
  (SELECT COUNT(*) FROM tenants)       AS tenants,      -- 6
  (SELECT COUNT(*) FROM animals)       AS animals,      -- 93
  (SELECT COUNT(*) FROM cases)         AS cases,        -- 52
  (SELECT COUNT(*) FROM evidences)     AS evidences,    -- 203
  (SELECT COUNT(*) FROM custody_records) AS custody,    -- 144
  (SELECT COUNT(*) FROM dossiers)      AS dossiers,     -- 52
  (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 · 23 controllers · 167 endpoints
JWT Auth · RBAC Guard · Tenant Interceptor · Audit Interceptor · Throttler
PostgreSQL 16 + PostGIS
26 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":"<seu-email>","password":"<sua-senha>"}' \
  | 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 · 26 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
  • 3.300+ 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.