Ajoute l'authentification Google en complément de la connexion par mot de passe. Le callback OAuth émet le même JWT que la connexion classique, donc le middleware d'authentification et ProtectedRoute restent inchangés. Backend - stratégie passport-google-oauth20 dans src/config/passport.js - routes GET /api/auth/google et /google/callback, documentées dans Swagger - un compte existant avec le même email est rattaché automatiquement au compte Google, et son email passe vérifié - les routes répondent 503 si les identifiants ne sont pas configurés, plutôt que de faire échouer le démarrage du serveur - login et changePassword ne comparent plus un hash inexistant sur les comptes sans mot de passe Base de données - password devient nullable - colonnes provider, providerId et avatarUrl, index unique sur le couple provider/providerId Frontend - page /auth/callback qui récupère le token et redirige selon le rôle - boutons Google de Connexion et Inscription branchés - boutons Facebook désactivés en attendant les identifiants Meta Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
142 lines
3.2 KiB
Plaintext
142 lines
3.2 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
enum Role {
|
|
CLIENT
|
|
EMPLOYEE
|
|
ADMIN
|
|
}
|
|
|
|
enum ClaimType {
|
|
STORE
|
|
ONLINE
|
|
}
|
|
|
|
enum ClaimStatus {
|
|
PENDING
|
|
DELIVERED
|
|
CANCELLED
|
|
}
|
|
|
|
enum AuthProvider {
|
|
LOCAL
|
|
GOOGLE
|
|
FACEBOOK
|
|
}
|
|
|
|
model User {
|
|
id Int @id @default(autoincrement())
|
|
firstname String
|
|
lastname String
|
|
email String @unique
|
|
// Nul pour les comptes créés via un provider externe (Google, Facebook) :
|
|
// ces utilisateurs n'ont jamais choisi de mot de passe chez nous.
|
|
password String?
|
|
role Role @default(CLIENT)
|
|
birthdate DateTime?
|
|
gender String?
|
|
marketingOptIn Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
|
|
isEmailVerified Boolean @default(false)
|
|
emailVerifyToken String?
|
|
emailVerifyExpires DateTime?
|
|
|
|
resetPasswordToken String?
|
|
resetPasswordExpires DateTime?
|
|
|
|
provider AuthProvider @default(LOCAL)
|
|
providerId String?
|
|
avatarUrl String?
|
|
|
|
tickets Ticket[]
|
|
participations Participation[]
|
|
grandPrizeWinner GrandPrizeWinner?
|
|
claimsValidated Claim[] @relation("EmployeeClaims")
|
|
|
|
@@unique([provider, providerId])
|
|
}
|
|
|
|
model Lot {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
description String?
|
|
value Float?
|
|
percentage Float
|
|
|
|
tickets Ticket[]
|
|
participations Participation[]
|
|
}
|
|
|
|
model Ticket {
|
|
id Int @id @default(autoincrement())
|
|
code String @unique
|
|
isUsed Boolean @default(false)
|
|
usedAt DateTime?
|
|
|
|
lotId Int
|
|
lot Lot @relation(fields: [lotId], references: [id])
|
|
|
|
userId Int?
|
|
user User? @relation(fields: [userId], references: [id])
|
|
|
|
participation Participation?
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model Participation {
|
|
id Int @id @default(autoincrement())
|
|
|
|
userId Int
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
ticketId Int @unique
|
|
ticket Ticket @relation(fields: [ticketId], references: [id])
|
|
|
|
lotId Int
|
|
lot Lot @relation(fields: [lotId], references: [id])
|
|
|
|
claim Claim?
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model Claim {
|
|
id Int @id @default(autoincrement())
|
|
|
|
status ClaimStatus @default(PENDING)
|
|
|
|
participationId Int @unique
|
|
participation Participation @relation(fields: [participationId], references: [id])
|
|
|
|
validatedByEmployeeId Int?
|
|
validatedByEmployee User? @relation("EmployeeClaims", fields: [validatedByEmployeeId], references: [id])
|
|
|
|
claimedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
}
|
|
|
|
model GrandPrizeWinner {
|
|
id Int @id @default(autoincrement())
|
|
|
|
userId Int @unique
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
prize String @default("Un an de thé d'une valeur de 360€")
|
|
drawnAt DateTime @default(now())
|
|
}
|
|
|
|
// Ligne unique de configuration : date de début du jeu-concours.
|
|
// Participation et réclamation des lots sont autorisées pendant 60 jours
|
|
// (30 jours de jeu + 30 jours supplémentaires) à compter de startDate.
|
|
model GameSettings {
|
|
id Int @id @default(autoincrement())
|
|
startDate DateTime @default(now())
|
|
createdAt DateTime @default(now())
|
|
}
|