generator client { provider = "prisma-client-js" binaryTargets = ["native", "linux-musl", "linux-musl-openssl-3.0.x"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") } model User { id String @id @default(uuid()) name String email String @unique password String role UserRole @default(VISITOR) avatar String? emailVerified Boolean @default(false) verificationToken String? @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt bio String? location String? countryId String? phone String? isSuspended Boolean @default(false) suspensionReason String? businesses Business? comments Comment[] conversations ConversationParticipant[] sentMessages Message[] reports MessageReport[] ratings Rating[] country Country? @relation(fields: [countryId], references: [id]) } model Business { id String @id @default(uuid()) name String category String suggestedCategory String? location String // Legacy location string countryId String? city String? description String logoUrl String coverUrl String? coverPosition String? @default("50% 50%") coverZoom Float? @default(1.0) videoUrl String? contactEmail String contactPhone String? socialLinks Json? verified Boolean @default(false) viewCount Int @default(0) rating Float @default(0.0) ratingCount Int @default(0) tags String[] isFeatured Boolean @default(false) founderName String? founderImageUrl String? keyMetric String? ownerId String @unique createdAt DateTime @default(now()) updatedAt DateTime @updatedAt slug String? @unique isActive Boolean @default(false) showEmail Boolean @default(true) showPhone Boolean @default(true) showSocials Boolean @default(true) websiteUrl String? isSuspended Boolean @default(false) suspensionReason String? plan Plan @default(STARTER) owner User @relation(fields: [ownerId], references: [id]) comments Comment[] conversations Conversation[] offers Offer[] ratings Rating[] country Country? @relation(fields: [countryId], references: [id]) categoryRef BusinessCategory? @relation(fields: [categoryId], references: [id]) categoryId String? } model BusinessCategory { id String @id @default(uuid()) name String @unique slug String @unique icon String? // Lucide icon name isActive Boolean @default(true) businesses Business[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Country { id String @id @default(uuid()) name String @unique code String @unique // ISO alpha-2 flag String? // Emoji or URL isActive Boolean @default(true) businesses Business[] users User[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model PricingPlan { id String @id @default(uuid()) tier Plan @unique name String priceXOF String yearlyPriceXOF String? priceEUR String yearlyPriceEUR String? description String features String[] offerLimit Int @default(1) recommended Boolean @default(false) color String @default("gray") updatedAt DateTime @updatedAt } model Offer { id String @id @default(uuid()) title String type OfferType price Float currency String @default("XOF") description String? imageUrl String active Boolean @default(true) businessId String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt business Business @relation(fields: [businessId], references: [id], onDelete: Cascade) } model BlogPost { id String @id @default(uuid()) title String slug String? @unique excerpt String content String author String date DateTime @default(now()) imageUrl String tags String[] @default([]) metaTitle String? metaDescription String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Interview { id String @id @default(uuid()) title String slug String? @unique guestName String companyName String role String type InterviewType thumbnailUrl String videoUrl String? content String? excerpt String date DateTime @default(now()) duration String? tags String[] @default([]) metaTitle String? metaDescription String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt } model Comment { id String @id @default(uuid()) content String authorId String businessId String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt author User @relation(fields: [authorId], references: [id], onDelete: Cascade) business Business @relation(fields: [businessId], references: [id], onDelete: Cascade) } model AnalyticsEvent { id String @id @default(uuid()) type String path String label String? value Float? metadata Json? ip String? country String? city String? browser String? os String? device String? referrer String? userId String? createdAt DateTime @default(now()) } model Rating { id String @id @default(uuid()) value Int comment String? reply String? replyAt DateTime? status RatingStatus @default(PENDING) userId String businessId String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt user User @relation(fields: [userId], references: [id], onDelete: Cascade) business Business @relation(fields: [businessId], references: [id], onDelete: Cascade) @@unique([userId, businessId]) } enum RatingStatus { PENDING APPROVED REJECTED } model Conversation { id String @id @default(uuid()) businessId String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt business Business @relation(fields: [businessId], references: [id], onDelete: Cascade) participants ConversationParticipant[] messages Message[] } model ConversationParticipant { id String @id @default(uuid()) userId String conversationId String isArchived Boolean @default(false) conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([userId, conversationId]) } model Message { id String @id @default(uuid()) content String senderId String conversationId String createdAt DateTime @default(now()) read Boolean @default(false) conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade) sender User @relation(fields: [senderId], references: [id], onDelete: Cascade) reports MessageReport[] } model MessageReport { id String @id @default(uuid()) reason String? messageId String reporterId String status ReportStatus @default(PENDING) createdAt DateTime @default(now()) message Message @relation(fields: [messageId], references: [id], onDelete: Cascade) reporter User @relation(fields: [reporterId], references: [id], onDelete: Cascade) } enum ReportStatus { PENDING RESOLVED DISMISSED } enum UserRole { VISITOR ENTREPRENEUR ADMIN } enum Plan { STARTER BOOSTER EMPIRE } enum OfferType { PRODUCT SERVICE } enum InterviewType { VIDEO ARTICLE } model SiteSetting { id String @id @default("singleton") siteName String @default("Afrohub") siteSlogan String @default("La plateforme de référence pour l'entrepreneuriat africain.") contactEmail String @default("support@afrohub.com") contactPhone String? @default("+225 00 00 00 00 00") address String? @default("Abidjan, Côte d'Ivoire") facebookUrl String? twitterUrl String? instagramUrl String? linkedinUrl String? footerText String? @default("© 2025 Afrohub. Tous droits réservés.") homeBlogShow Boolean @default(true) homeBlogTitle String @default("Derniers Articles") homeBlogSubtitle String @default("Toutes les actualités de l'entrepreneuriat africain.") homeBlogCount Int @default(3) homeBlogSelection String @default("latest") homeCategories String[] @default(["Technologie & IT", "Agriculture & Agrobusiness", "Mode & Textile", "Cosmétique & Beauté"]) resetPasswordSubject String @default("Réinitialisation de votre mot de passe - Afrohub") resetPasswordTemplate String @default("
Bonjour {name},
Vous avez demandé la réinitialisation de votre mot de passe. Cliquez sur le bouton ci-dessous pour choisir un nouveau mot de passe :
Ce lien expirera dans 1 heure. Si vous n'avez pas demandé cette réinitialisation, vous pouvez ignorer cet email.
© 2025 {siteName}. Tous droits réservés.
Bonjour {name},
Merci de vous être inscrit sur {siteName}. Pour finaliser la création de votre compte, merci de vérifier votre adresse email en cliquant sur le bouton ci-dessous :
Si vous n'avez pas créé de compte sur notre plateforme, vous pouvez ignorer cet email.
© 2025 {siteName}. Tous droits réservés.