first commit
This commit is contained in:
322
docs/04-base-de-dados.md
Normal file
322
docs/04-base-de-dados.md
Normal file
@@ -0,0 +1,322 @@
|
||||
# 4. Modelação da Base de Dados
|
||||
|
||||
## 4.1 Diagrama de Entidade-Relacionamento (ERD)
|
||||
|
||||
```
|
||||
┌──────────────┐ ┌──────────────────┐ ┌──────────────┐
|
||||
│ User │ │ Animal │ │ Shelter │
|
||||
├──────────────┤ ├──────────────────┤ ├──────────────┤
|
||||
│ id (PK) │ │ id (PK) │ │ id (PK) │
|
||||
│ email │ │ shelterId (FK) ──┼──────►│ name │
|
||||
│ password │ │ name │ │ district │
|
||||
│ name │ │ species │ │ address │
|
||||
│ birthdate │ │ breed │ │ latitude │
|
||||
│ district │ │ age │ │ longitude │
|
||||
│ role │ │ sex │ │ phone │
|
||||
│ darkMode │ │ sterilized │ │ email │
|
||||
│ createdAt │ │ status │ │ openHours │
|
||||
└──────┬───────┘ │ urgent │ │ passwordHash │
|
||||
│ │ description │ │ createdAt │
|
||||
│ │ createdAt │ └──────┬───────┘
|
||||
│ └────────┬─────────┘ │
|
||||
│ │ │
|
||||
│ ┌────────▼────────┐ ┌────────▼────────┐
|
||||
│ │ AnimalPhoto │ │ ShelterNeed │
|
||||
│ ├─────────────────┤ ├─────────────────┤
|
||||
│ │ id (PK) │ │ id (PK) │
|
||||
│ │ animalId (FK) │ │ shelterId (FK) │
|
||||
│ │ url │ │ type │
|
||||
│ │ isPrimary │ │ description │
|
||||
│ └─────────────────┘ │ urgent │
|
||||
│ │ active │
|
||||
│ └─────────────────┘
|
||||
│
|
||||
├──────────────────────────────────────────────────────────┐
|
||||
│ │
|
||||
┌──────▼───────────────┐ ┌──────────▼──────┐
|
||||
│ Reservation │ │ Donation │
|
||||
├──────────────────────┤ ├─────────────────┤
|
||||
│ id (PK) │ │ id (PK) │
|
||||
│ userId (FK) ─────────┘ │ userId (FK) │
|
||||
│ animalId (FK) │ │ shelterId (FK) │
|
||||
│ date │ │ type │
|
||||
│ status │ │ details (JSON) │
|
||||
│ emailSent │ │ status │
|
||||
│ createdAt │ │ createdAt │
|
||||
└──────────────────────┘ └────────┬────────┘
|
||||
│
|
||||
┌────────▼────────┐
|
||||
│ Payment │
|
||||
├─────────────────┤
|
||||
│ id (PK) │
|
||||
│ donationId (FK) │
|
||||
│ stripeId │
|
||||
│ amount │
|
||||
│ currency │
|
||||
│ status │
|
||||
│ createdAt │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4.2 Descrição das Entidades
|
||||
|
||||
| Entidade | Descrição | Relações |
|
||||
|---|---|---|
|
||||
| `User` | Utilizador registado na plataforma | Tem muitas `Reservation` e `Donation` |
|
||||
| `Shelter` | Canil ou associação de protecção animal | Tem muitos `Animal`, recebe `Donation`, tem `ShelterNeed` |
|
||||
| `Animal` | Animal disponível para adopção | Pertence a um `Shelter`, tem `AnimalPhoto` e `Reservation` |
|
||||
| `Reservation` | Reserva de adopção de um animal | Pertence a `User` e `Animal` |
|
||||
| `Donation` | Doação (monetária, ração ou brinquedos) | Pertence a `User` e `Shelter`, tem `Payment` opcional |
|
||||
| `Payment` | Registo do pagamento processado pelo Stripe | Associado a `Donation` do tipo monetário |
|
||||
| `AnimalPhoto` | Fotografia de um animal | Pertence a `Animal` |
|
||||
| `ShelterNeed` | Necessidade actual do canil | Pertence a `Shelter` |
|
||||
|
||||
---
|
||||
|
||||
## 4.3 Esquema Prisma Completo
|
||||
|
||||
```prisma
|
||||
// prisma/schema.prisma
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
// ─── Enums ──────────────────────────────────────────────────────
|
||||
|
||||
enum UserRole {
|
||||
USER
|
||||
SHELTER_ADMIN
|
||||
ADMIN
|
||||
}
|
||||
|
||||
enum Species {
|
||||
DOG
|
||||
CAT
|
||||
OTHER
|
||||
}
|
||||
|
||||
enum Sex {
|
||||
MALE
|
||||
FEMALE
|
||||
}
|
||||
|
||||
enum AnimalStatus {
|
||||
AVAILABLE
|
||||
RESERVED
|
||||
ADOPTED
|
||||
}
|
||||
|
||||
enum DonationType {
|
||||
MONETARY
|
||||
FOOD
|
||||
TOYS
|
||||
}
|
||||
|
||||
enum ReservationStatus {
|
||||
PENDING
|
||||
CONFIRMED
|
||||
CANCELLED
|
||||
COMPLETED
|
||||
}
|
||||
|
||||
enum DonationStatus {
|
||||
PENDING
|
||||
CONFIRMED
|
||||
DELIVERED
|
||||
CANCELLED
|
||||
}
|
||||
|
||||
// ─── Models ─────────────────────────────────────────────────────
|
||||
|
||||
model User {
|
||||
id String @id @default(cuid())
|
||||
email String @unique
|
||||
password String // bcrypt hash — nunca em texto simples
|
||||
name String
|
||||
birthdate DateTime
|
||||
district String
|
||||
role UserRole @default(USER)
|
||||
darkMode Boolean @default(false)
|
||||
emailVerified Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
reservations Reservation[]
|
||||
donations Donation[]
|
||||
|
||||
@@index([email])
|
||||
@@index([district])
|
||||
}
|
||||
|
||||
model Shelter {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
district String
|
||||
address String
|
||||
latitude Float
|
||||
longitude Float
|
||||
phone String
|
||||
email String @unique
|
||||
passwordHash String
|
||||
description String?
|
||||
website String?
|
||||
// JSON: { mon: "09:00-18:00", tue: "09:00-18:00", ... , sun: null }
|
||||
openHours Json
|
||||
verified Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
animals Animal[]
|
||||
donations Donation[]
|
||||
needs ShelterNeed[]
|
||||
|
||||
@@index([district])
|
||||
}
|
||||
|
||||
model Animal {
|
||||
id String @id @default(cuid())
|
||||
shelterId String
|
||||
shelter Shelter @relation(fields: [shelterId], references: [id])
|
||||
name String
|
||||
species Species
|
||||
breed String? // relevante para DOG e CAT
|
||||
ageMonths Int // idade em meses para precisão
|
||||
sex Sex
|
||||
sterilized Boolean
|
||||
status AnimalStatus @default(AVAILABLE)
|
||||
urgent Boolean @default(false)
|
||||
description String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
photos AnimalPhoto[]
|
||||
reservations Reservation[]
|
||||
|
||||
@@index([shelterId])
|
||||
@@index([species])
|
||||
@@index([status])
|
||||
@@index([district: false]) // via shelter — para queries por localidade
|
||||
}
|
||||
|
||||
model AnimalPhoto {
|
||||
id String @id @default(cuid())
|
||||
animalId String
|
||||
animal Animal @relation(fields: [animalId], references: [id], onDelete: Cascade)
|
||||
url String
|
||||
isPrimary Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([animalId])
|
||||
}
|
||||
|
||||
model Reservation {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
animalId String
|
||||
animal Animal @relation(fields: [animalId], references: [id])
|
||||
date DateTime
|
||||
status ReservationStatus @default(PENDING)
|
||||
emailSent Boolean @default(false)
|
||||
notes String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([userId])
|
||||
@@index([animalId])
|
||||
@@index([date])
|
||||
}
|
||||
|
||||
model Donation {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
shelterId String
|
||||
shelter Shelter @relation(fields: [shelterId], references: [id])
|
||||
type DonationType
|
||||
// Para FOOD: { foodType: "dry|wet", animalType: "dog|cat", ageGroup: "adult|puppy" }
|
||||
// Para TOYS: { category: "chew|plush|interactive" }
|
||||
// Para MONETARY: { amount: 25.00, currency: "EUR" }
|
||||
// Partilhado: { deliveryMethod: "pickup|home_delivery", address?: "..." }
|
||||
details Json
|
||||
status DonationStatus @default(PENDING)
|
||||
emailSent Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
payment Payment?
|
||||
|
||||
@@index([userId])
|
||||
@@index([shelterId])
|
||||
@@index([type])
|
||||
}
|
||||
|
||||
model Payment {
|
||||
id String @id @default(cuid())
|
||||
donationId String @unique
|
||||
donation Donation @relation(fields: [donationId], references: [id])
|
||||
stripePaymentId String @unique
|
||||
amount Int // em cêntimos (ex: 2500 = 25,00€)
|
||||
currency String @default("eur")
|
||||
status String // stripe payment status
|
||||
receiptUrl String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model ShelterNeed {
|
||||
id String @id @default(cuid())
|
||||
shelterId String
|
||||
shelter Shelter @relation(fields: [shelterId], references: [id])
|
||||
type String // "food_dry_dog", "toys", "blankets", etc.
|
||||
description String?
|
||||
urgent Boolean @default(false)
|
||||
active Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([shelterId])
|
||||
@@index([active])
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4.4 Estratégia de Indexação
|
||||
|
||||
Os índices foram definidos com base nos filtros mais comuns da aplicação:
|
||||
|
||||
| Índice | Tabela | Motivo |
|
||||
|---|---|---|
|
||||
| `email` | User | Login — lookup por email frequente |
|
||||
| `district` | User, Shelter | Filtros por localidade |
|
||||
| `shelterId` | Animal | Listar animais de um canil |
|
||||
| `species`, `status` | Animal | Filtros principais da listagem |
|
||||
| `userId` | Reservation, Donation | Histórico do utilizador |
|
||||
| `animalId` | Reservation | Verificar disponibilidade do animal |
|
||||
| `type`, `active` | ShelterNeed | Listar necessidades activas por tipo |
|
||||
|
||||
---
|
||||
|
||||
## 4.5 Migrações
|
||||
|
||||
As migrações são geridas automaticamente pelo Prisma:
|
||||
|
||||
```bash
|
||||
# Criar nova migração após alterar schema.prisma
|
||||
npx prisma migrate dev --name descricao_da_alteracao
|
||||
|
||||
# Aplicar migrações em produção
|
||||
npx prisma migrate deploy
|
||||
|
||||
# Visualizar base de dados no browser (Prisma Studio)
|
||||
npx prisma studio
|
||||
```
|
||||
Reference in New Issue
Block a user