Uma aplicação moderna de encurtamento de URLs construída com React, Node.js e implantada na AWS com infraestrutura como código.
- Framework: React + TypeScript + Vite
- Styling: Tailwind CSS
- Estado: React Query (TanStack Query)
- Deploy: AWS CloudFront + S3
- SSL: AWS Certificate Manager (ACM)
- Framework: Fastify + TypeScript
- Validação: Zod
- Database: PostgreSQL (Neon)
- Storage: Cloudflare R2
- Deploy: AWS ECS Fargate
- Load Balancer: AWS Application Load Balancer
- Cloud Provider: AWS
- DNS: Cloudflare
- IaC: Terraform
- CI/CD: GitHub Actions
- Containerização: Docker
- Monitoramento: CloudWatch
- Frontend: https://brev-ly.uk
- API: https://api.brev-ly.uk
- Documentação: https://api.brev-ly.uk/docs
- Encurtamento de URLs com slug personalizado
- HTTPS automático: URLs sem protocolo recebem https:// automaticamente
- Segurança: URLs HTTP são rejeitadas (apenas HTTPS aceito)
- Listagem de links com paginação
- Contador de visitas
- Redirecionamento automático
- Exclusão de links
- Exportação para CSV
- Interface responsiva com UX otimizada
- API RESTful com documentação Swagger
- Health checks
- SSL/TLS em todos os endpoints
- CORS configurado
Método | Endpoint | Descrição |
---|---|---|
GET |
/health |
Health check |
POST |
/shorten |
Criar link encurtado |
GET |
/ |
Listar links (paginado) |
PATCH |
/shortUrl/:url |
Obter URL original + incrementar visitas |
DELETE |
/shortUrl/:id |
Deletar link |
POST |
/export |
Exportar links para CSV |
# Health check
curl https://api.brev-ly.uk/health
# Criar link (HTTPS automático)
curl -X POST https://api.brev-ly.uk/v1/link/shorten \
-H "Content-Type: application/json" \
-d '{"originalUrl": "example.com", "shortUrl": "exemplo"}'
# A API automaticamente converte para: https://example.com
# Criar link com HTTPS explícito (também funciona)
curl -X POST https://api.brev-ly.uk/v1/link/shorten \
-H "Content-Type: application/json" \
-d '{"originalUrl": "https://github.com/user/repo", "shortUrl": "repo"}'
# ❌ URLs HTTP são rejeitadas
curl -X POST https://api.brev-ly.uk/v1/link/shorten \
-H "Content-Type: application/json" \
-d '{"originalUrl": "http://insecure.com", "shortUrl": "insecure"}'
# Retorna: 400 Bad Request - "URLs HTTP não são permitidas. Use HTTPS apenas."
# Listar links
curl "https://api.brev-ly.uk/v1/link/?page=1&limit=10"
# Redirecionar (incrementa visita)
curl -X PATCH https://api.brev-ly.uk/v1/link/shortUrl/exemplo
# Deletar link
curl -X DELETE https://api.brev-ly.uk/v1/link/shortUrl/exemplo
example.com
→https://example.com
github.com/user/repo
→https://github.com/user/repo
subdomain.site.com.br
→https://subdomain.site.com.br
https://site.com
→https://site.com
(mantém como está)
http://site.com
→ Erro 400: "URLs HTTP não são permitidas. Use HTTPS apenas."ftp://site.com
→ Erro 400: URL inválidainvalid-url
→ Erro 400: URL inválida
{
"react": "^18.3.1",
"typescript": "~5.6.2",
"@tanstack/react-query": "^5.56.2",
"tailwindcss": "^3.4.13",
"vite": "^5.4.8"
}
{
"fastify": "^5.0.0",
"drizzle-orm": "^0.33.0",
"zod": "^3.23.8",
"@aws-sdk/client-s3": "^3.658.1"
}
- VPC: Rede privada com subnets públicas e privadas
- ECS Fargate: Containers serverless para a API
- Application Load Balancer: Balanceamento de carga com SSL
- CloudFront: CDN global para o frontend
- S3: Armazenamento de assets estáticos
- Secrets Manager: Gerenciamento seguro de credenciais
- CloudWatch: Logs e monitoramento
- Auto Scaling: Escalonamento automático baseado em CPU/memória
Internet
│
├─── CloudFront ──► S3 (Frontend)
│ │
│ CloudFlare DNS
│ │
└─── ALB ──► ECS Fargate (API)
│
VPC (Private Subnets)
│
RDS/Neon (Database)
- Node.js 20+
- pnpm
- Docker
- AWS CLI
- Terraform
# Clone o repositório
git clone https://github.com/gabrielmatsan/brev-ly.git
cd brev-ly
# Backend
cd server
pnpm install
pnpm dev
# Frontend
cd ../web
pnpm install
pnpm dev
NODE_ENV=development
DATAPORT=8080
FRONTEND_URL=http://localhost:5173
DATABASE_URL=postgresql://...
CLOUDFLARE_ACCOUNT_ID=...
CLOUDFLARE_ACCESS_KEY_ID=...
CLOUDFLARE_SECRET_ACCESS_KEY=...
CLOUDFLARE_BUCKET=...
CLOUDFLARE_PUBLIC_URL=...
NODE_ENV=development
VITE_FRONTEND_URL=http://localhost:5173
VITE_BACKEND_URL=http://localhost:8080
cd terraform
# Configurar variáveis
cp terraform.tfvars.example terraform.tfvars
# Editar terraform.tfvars com seus valores
# Deploy da infraestrutura
terraform init
terraform plan
terraform apply
O deploy é automático via GitHub Actions:
- Push para
main
com mudanças emserver/
→ Deploy da API - Push para
main
com mudanças emweb/
→ Deploy do Frontend
.github/workflows/ci-cd-api.yml
- Deploy da API.github/workflows/ci-cd-front-end.yml
- Deploy do Frontend.github/workflows/pr.yml
- Testes em Pull Requests
- API:
/ecs/brev-ly
- ALB:
/aws/alb/brev-ly
- CPU/Memory do ECS: Auto scaling configurado
- Erros do ALB: Alarme para 5xx errors
- Health checks: Monitoramento contínuo
- ECS:
curl -f http://localhost:8080/health
- ALB:
GET /health
(porta 8080) - Interval: 30s, Timeout: 5s, Retries: 3
- Certificados: AWS Certificate Manager
- Protocolo: TLS 1.2+
- Validação: DNS via Cloudflare
- Credenciais: AWS Secrets Manager
- GitHub Registry: Secrets para pull de imagens
- Environment Variables: Secrets para configuração da aplicação
- VPC: Subnets privadas para ECS
- Security Groups: Portas específicas (80, 443, 8080)
- ALB: Público, ECS privado
FROM node:20-alpine AS runner
RUN apk add --no-cache curl
# Multi-stage build para otimização
- Base: Alpine Linux (segura e leve)
- Tamanho: ~50MB (otimizada)
- Health check: Curl integrado
- User: Non-root (1000)
- CDN: CloudFront com cache global
- Compressão: Gzip/Brotli habilitado
- HTTP/2: Suporte completo
- Container: 512MB RAM, 256 CPU units
- Auto Scaling: 0-2 instâncias baseado em CPU/memória
- Database: Connection pooling
- Cache: Headers otimizados
# Health check
curl https://api.brev-ly.uk/health
# Criar link
curl -X POST https://api.brev-ly.uk/v1/link/shorten \
-H "Content-Type: application/json" \
-d '{"originalUrl": "https://example.com", "shortUrl": "test"}'
# Listar links
curl "https://api.brev-ly.uk/v1/link/?page=1&limit=10"
- Acesse: https://brev-ly.uk
- Teste criação de links
- Teste redirecionamento
- Teste listagem e exclusão
- Verificar ECS tasks:
aws ecs describe-services --cluster brev-ly-ecs-cluster --services brev-ly-ecs-service
- Verificar logs: CloudWatch →
/ecs/brev-ly
- Verificar CloudFront: Invalidar cache
- Verificar S3: Bucket policy e conteúdo
- Verificar DNS: Cloudflare proxy desabilitado
- Verificar logs do container
- Testar endpoint manualmente:
curl https://api.brev-ly.uk/health
- Verificar task definition
brev-ly/
├── server/ # Backend API
│ ├── src/
│ │ ├── app.ts # Configuração do Fastify
│ │ ├── app.routes.ts # Rotas principais
│ │ ├── link/ # Módulo de links
│ │ └── shared/ # Utilitários compartilhados
│ ├── Dockerfile # Imagem Docker
│ └── healthcheck.js # Script de health check
├── web/ # Frontend React
│ ├── src/
│ │ ├── pages/ # Páginas da aplicação
│ │ ├── hooks/ # Hooks customizados
│ │ └── lib/ # Utilitários e API client
│ └── dist/ # Build de produção
├── terraform/ # Infraestrutura como código
│ ├── *.tf # Recursos AWS
│ └── terraform.tfvars # Variáveis de configuração
└── .github/
├── workflows/ # CI/CD pipelines
└── ecs/ # Task definitions
- Fork o projeto
- Crie uma branch para sua feature (
git checkout -b feature/nova-funcionalidade
) - Commit suas mudanças (
git commit -am 'Adiciona nova funcionalidade'
) - Push para a branch (
git push origin feature/nova-funcionalidade
) - Abra um Pull Request
Este projeto está sob a licença MIT. Veja o arquivo LICENSE para mais detalhes.
- ✅ TypeScript: Type safety em todo o projeto
- ✅ Infraestrutura como Código: Terraform para AWS
- ✅ CI/CD: GitHub Actions com deploy automático
- ✅ Containerização: Docker multi-stage builds
- ✅ Monitoramento: CloudWatch logs e métricas
- ✅ Segurança: Secrets Manager, VPC, SSL/TLS
- ✅ Performance: CDN, auto scaling, otimizações
- ✅ Documentação: Swagger/OpenAPI para API
Desenvolvido por Gabriel Santos 🚀