API REST completa para gerenciamento seguro de documentos β com autenticaΓ§Γ£o JWT, upload de PDF, versionamento automΓ‘tico, verificaΓ§Γ£o de integridade via hash SHA-256, rate limiting e dashboard web.
π Demo em produΓ§Γ£o: docvault-api-cl21.vercel.app
| Camada | Tecnologia |
|---|---|
| Framework | Next.js 14+ (App Router) + TypeScript |
| Banco de dados | Supabase (PostgreSQL) |
| AutenticaΓ§Γ£o | Supabase Auth (JWT) |
| Storage | Supabase Storage |
| Rate Limiting | Upstash Redis |
| Testes | Vitest + Testing Library |
| Deploy | Vercel |
- Registro e login com email + senha
- SessΓ΅es JWT via Supabase Auth
- Middleware de autenticaΓ§Γ£o em todas as rotas protegidas
- RenovaΓ§Γ£o automΓ‘tica de tokens
- Upload de PDFs (mΓ‘x. 10MB)
- CRUD completo com autorizaΓ§Γ£o por ownership
- Filtros por status e busca por tΓtulo
- PaginaΓ§Γ£o configurΓ‘vel
- HistΓ³rico automΓ‘tico a cada novo upload
- Rastreio de quem criou cada versΓ£o e notas de mudanΓ§a
- Hash SHA-256 gerado no upload e salvo no banco
- Endpoint de verificaΓ§Γ£o: compara o hash do arquivo enviado com o registrado
- ComparaΓ§Γ£o timing-safe para evitar timing attacks
- Eventos automaticamente disparados:
document.created,document.updated,document.deleted,document.signed,version.created - Assinatura HMAC-SHA256 em todos os payloads
- Endpoint receptor protegido por
X-Webhook-Secret
- LimitaΓ§Γ£o por IP via Upstash Redis (sliding window)
- Rotas de autenticaΓ§Γ£o: 10 req/min
- Demais rotas: 60 req/min
- Headers informativos:
X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset - Fail-open: se o Redis estiver indisponΓvel, a API continua funcionando
- Interface web completa acessΓvel em
/ - Login e cadastro integrados
- Listagem, busca e atualizaΓ§Γ£o de status de documentos
- Drag-and-drop para upload
- VerificaΓ§Γ£o de integridade visual
- NotificaΓ§Γ΅es toast em tempo real
git clone https://github.com/Junio243/docvault-api.git
cd docvault-api
npm install- Crie um projeto em supabase.com
- VΓ‘ em SQL Editor β New query
- Cole e execute o conteΓΊdo de
supabase/schema.sqlO script cria as tabelas, Γndices, polΓticas RLS e o bucket de storage automaticamente.
cp .env.example .env.localEdite .env.local:
# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://seu-projeto.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=sua-anon-key
SUPABASE_SERVICE_ROLE_KEY=sua-service-role-key
NEXT_PUBLIC_APP_URL=http://localhost:3000
# Webhook
WEBHOOK_SECRET=uma-string-secreta-qualquer
# Upstash Redis β Rate Limiting (opcional)
# Crie grΓ‘tis em https://console.upstash.com/redis
UPSTASH_REDIS_REST_URL=https://...
UPSTASH_REDIS_REST_TOKEN=...Nota: As variΓ‘veis do Upstash sΓ£o opcionais. Sem elas, o rate limiting Γ© desativado silenciosamente e tudo continua funcionando.
npm run devAcesse: http://localhost:3000
# Rodar todos os testes
npm test
# Modo watch (re-executa ao salvar)
npm run test:watch
# Com relatΓ³rio de cobertura
npm run test:coverageCobertura atual: 26 testes passando em 3 suites:
tests/lib/crypto.test.tsβ hash SHA-256, HMAC, tokenstests/lib/api-response.test.tsβ helpers de resposta padronizadatests/api/documents.test.tsβ rota de listagem de documentos
Local: http://localhost:3000/api
ProduΓ§Γ£o: https://docvault-api-cl21.vercel.app/api
Todas as rotas protegidas requerem o cookie de sessΓ£o Supabase (gerenciado automaticamente pelo browser) ou Bearer Token:
Authorization: Bearer <access_token>{ "email": "[email protected]", "password": "senha123" }{ "email": "[email protected]", "password": "senha123" }Resposta:
{
"success": true,
"data": {
"user": { "id": "uuid", "email": "...", "created_at": "..." },
"session": {
"access_token": "...",
"refresh_token": "...",
"expires_at": 1234567890,
"expires_in": 3600
}
}
}| Param | Tipo | Default | DescriΓ§Γ£o |
|---|---|---|---|
page |
number | 1 |
PΓ‘gina |
limit |
number | 10 |
Itens por pΓ‘gina (mΓ‘x. 50) |
status |
string | β | Filtra: draft, pending, signed, archived |
search |
string | β | Busca no tΓtulo |
| Campo | ObrigatΓ³rio | DescriΓ§Γ£o |
|---|---|---|
file |
β | Arquivo PDF (mΓ‘x. 10MB) |
title |
β | TΓtulo do documento (1β255 chars) |
status |
β | Status inicial (default: draft) |
Retorna todas as versΓ΅es em ordem decrescente.
Envia um arquivo PDF e verifica se o hash SHA-256 bate com o armazenado.
{
"success": true,
"data": {
"valid": true,
"document_id": "uuid",
"version": 2,
"stored_hash": "abc123...",
"provided_hash": "abc123...",
"message": "Integridade verificada: O arquivo Γ© idΓͺntico ao registrado"
}
}Retorna as informaΓ§Γ΅es do hash sem realizar comparaΓ§Γ£o.
Endpoint receptor de eventos. Requer o header:
X-Webhook-Secret: <WEBHOOK_SECRET>| Evento | Disparado quando |
|---|---|
document.created |
Novo documento criado |
document.updated |
Documento atualizado |
document.deleted |
Documento deletado |
document.signed |
Status alterado para signed |
version.created |
Novo arquivo enviado (nova versΓ£o) |
{
"event": "document.signed",
"document_id": "uuid",
"timestamp": "2026-03-14T01:00:00Z",
"data": { "signed_by": "user-uuid", "signed_at": "..." }
}X-Webhook-Signature: <hmac-sha256-do-payload>
X-Webhook-Event: document.signed
X-Webhook-Secret: <secret>
Content-Type: application/jsonconst crypto = require('crypto');
function verifyWebhook(payload, signature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(signature),
Buffer.from(expected)
);
}{
"success": false,
"error": { "code": "ERROR_CODE", "message": "DescriΓ§Γ£o" }
}| CΓ³digo | HTTP | DescriΓ§Γ£o |
|---|---|---|
UNAUTHORIZED |
401 | Token ausente ou invΓ‘lido |
FORBIDDEN |
403 | Sem permissΓ£o |
NOT_FOUND |
404 | Recurso nΓ£o existe |
VALIDATION_ERROR |
400 | Dados invΓ‘lidos (Zod) |
FILE_REQUIRED |
400 | Arquivo nΓ£o enviado |
INVALID_FILE_TYPE |
400 | Apenas PDF aceito |
FILE_TOO_LARGE |
400 | Arquivo acima de 10MB |
NO_HASH_REGISTERED |
400 | Documento sem hash para verificar |
RATE_LIMIT_EXCEEDED |
429 | Muitas requisiΓ§Γ΅es |
INTERNAL_ERROR |
500 | Erro interno |
docvault-api/
βββ app/
β βββ page.tsx # Dashboard UI
β βββ layout.tsx
β βββ globals.css
β βββ components/
β β βββ Toast.tsx
β β βββ UploadModal.tsx
β βββ api/
β βββ auth/
β β βββ login/route.ts
β β βββ logout/route.ts
β β βββ me/route.ts
β β βββ refresh/route.ts
β β βββ signup/route.ts
β βββ documents/
β β βββ route.ts
β β βββ [id]/
β β βββ route.ts
β β βββ verify/route.ts
β β βββ versions/route.ts
β βββ webhooks/route.ts
βββ lib/
β βββ api-response.ts # Helpers de resposta padronizada
β βββ auth.ts # getCurrentUser, requireAuth
β βββ crypto.ts # SHA-256, HMAC, tokens seguros
β βββ ratelimit.ts # Upstash rate limiting
β βββ storage.ts # Upload/download Supabase Storage
β βββ supabase.ts # Clientes server/service/browser
β βββ webhook.ts # Disparo de eventos
βββ tests/
β βββ setup.ts
β βββ api/documents.test.ts
β βββ lib/
β βββ api-response.test.ts
β βββ crypto.test.ts
βββ types/
β βββ index.ts
β βββ supabase.ts
βββ supabase/
β βββ schema.sql # Schema v2 completo
β βββ seed.sql
βββ middleware.ts # Auth + Rate Limiting
βββ vitest.config.ts
βββ next.config.js
βββ tsconfig.json
βββ package.json
- Conecte o repositΓ³rio em vercel.com
- Adicione as variΓ‘veis de ambiente no painel da Vercel
- Deploy automΓ‘tico a cada push na
main
MIT β livre para usar e adaptar.