6.5 KiB
3. Arquitectura do Sistema
3.1 Visão Geral
A arquitectura da PawLink segue o padrão de aplicação web moderna com separação clara entre frontend, backend e serviços externos. Adoptamos uma abordagem server-first com Next.js, que permite renderização no servidor (SSR) para melhor SEO e desempenho inicial, combinada com componentes interactivos no cliente onde necessário.
┌─────────────────────────────────────────────────────────────┐
│ CLIENTE (Browser) │
│ React 18 · Tailwind CSS · TanStack Query │
└───────────────────────┬─────────────────────────────────────┘
│ HTTPS
┌───────────────────────▼─────────────────────────────────────┐
│ VERCEL (Edge Network) │
│ Next.js 14 — SSR · API Routes · Middleware │
├──────────────┬──────────────┬───────────────────────────────┤
│ Auth Layer │ API Routes │ Static Assets (CDN) │
│ NextAuth.js │ Prisma ORM │ Cloudflare │
└──────┬───────┴──────┬───────┴───────────────────────────────┘
│ │
┌──────▼──────┐ ┌─────▼──────────────────────────────────────┐
│ Supabase │ │ Serviços Externos │
│ PostgreSQL │ │ Stripe · Resend · Anthropic · Upstash │
│ + Storage │ │ │
└─────────────┘ └──────────────────────────────────────────────┘
3.2 Camadas da Arquitectura
Camada de Apresentação (Frontend)
| Tecnologia | Função |
|---|---|
| Next.js 14+ (App Router) | Framework principal — SSR, routing, optimização de imagens |
| TypeScript | Tipagem estática para reduzir bugs em desenvolvimento |
| Tailwind CSS | Estilos utilitários responsivos e consistentes |
| shadcn/ui | Componentes acessíveis (ARIA) e personalizáveis |
| TanStack Query | Cache de dados do servidor, loading/error states |
| Zustand | Estado global da aplicação (sessão, preferências UI) |
| React Hook Form + Zod | Formulários com validação type-safe |
Camada de Lógica de Negócio (Backend)
| Tecnologia | Função |
|---|---|
| Next.js API Routes | Endpoints serverless co-localizados com o frontend |
| NextAuth.js | Autenticação completa com middleware de protecção de rotas |
| Prisma ORM | Acesso type-safe à base de dados com migrações automáticas |
| Zod | Validação rigorosa de todos os dados de entrada |
| bcryptjs | Hash seguro de palavras-passe |
Camada de Dados
| Tecnologia | Função |
|---|---|
| PostgreSQL via Supabase | Base de dados relacional principal |
| Supabase Storage | Armazenamento de imagens de animais e documentos |
| Upstash Redis | Cache de sessões e rate limiting |
Serviços Externos
| Serviço | Função |
|---|---|
| Stripe | Processamento de pagamentos (Cartão, MBWay via Payment Element) |
| Resend + react-email | Envio de emails transaccionais com templates profissionais |
| Anthropic Claude API | IA para match inteligente e chatbot de suporte |
| Cloudflare | CDN global, protecção DDoS, cache de assets |
| Sentry | Monitorização de erros em produção |
| Vercel Analytics | Core Web Vitals e métricas de performance |
3.3 Fluxo de Dados — Adopção
Utilizador
│
▼
[1] GET / → Next.js SSR → Prisma query → PostgreSQL
│ Renderiza lista de animais no servidor
│
▼
[2] Aplica filtros → TanStack Query → GET /api/animals?district=Lisboa&species=DOG
│
▼
[3] API Route valida params (Zod) → Prisma query com WHERE clause
│
▼
[4] Resposta JSON → React actualiza componentes AnimalGrid
│
▼
[5] Clica "Adoptar" → Middleware Next.js verifica sessão JWT
│ (sem sessão → redirect /login)
│
▼
[6] Selecciona data → POST /api/reservations { animalId, date }
│
▼
[7] API Route valida (Zod) → Prisma: UPDATE animal SET status='RESERVED'
→ Prisma: CREATE reservation
│
▼
[8] Resend envia email de confirmação com template react-email
│
▼
[9] Resposta 201 → TanStack Query invalida cache → UI actualiza estado do animal
3.4 Fluxo de Dados — Doação Monetária
[1] Utilizador selecciona canil e montante
[2] POST /api/donations/intent → Stripe cria PaymentIntent
[3] Frontend renderiza Stripe Payment Element (dados do cartão tratados pelo Stripe)
[4] Stripe processa pagamento → webhook POST /api/payments/webhook
[5] API Route verifica assinatura HMAC do webhook
[6] Prisma: UPDATE donation SET status='COMPLETED'
[7] Resend envia recibo de doação
3.5 Decisões de Arquitectura
Porque Next.js e não SPA pura (Vite/React)?
O SEO é crítico para uma plataforma de adopção — os animais devem aparecer nos resultados de pesquisa do Google. Com SSR, a página /animals/bobi-labrador-lisboa renderiza HTML completo no servidor, indexável pelos motores de busca. Uma SPA devolveria apenas HTML vazio.
Porque Supabase e não base de dados gerida manualmente?
O Supabase oferece PostgreSQL gerido, storage de ficheiros, autenticação e realtime numa única plataforma com free tier generoso. Reduz a complexidade operacional para uma equipa pequena sem comprometer escalabilidade.
Porque Stripe e não Paypal?
O Stripe tem suporte nativo a MBWay (método de pagamento dominante em Portugal), SEPA Direct Debit e MB Multibanco através do Stripe Payment Element. Tem a melhor integração com o ecossistema Node.js/TypeScript e é PCI DSS Level 1.