monorepo admin supp prisma
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "prisma generate && next build",
|
||||
"build": "prisma generate --schema=../prisma/schema.prisma && next build",
|
||||
"start": "next start -p 3000",
|
||||
"lint": "eslint"
|
||||
},
|
||||
|
||||
Binary file not shown.
@@ -1,459 +0,0 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "RatingStatus" AS ENUM ('PENDING', 'APPROVED', 'REJECTED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ReportStatus" AS ENUM ('PENDING', 'RESOLVED', 'DISMISSED');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "UserRole" AS ENUM ('VISITOR', 'ENTREPRENEUR', 'ADMIN');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "Plan" AS ENUM ('STARTER', 'BOOSTER', 'EMPIRE');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "OfferType" AS ENUM ('PRODUCT', 'SERVICE');
|
||||
|
||||
-- CreateEnum
|
||||
CREATE TYPE "InterviewType" AS ENUM ('VIDEO', 'ARTICLE');
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "User" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"email" TEXT NOT NULL,
|
||||
"password" TEXT NOT NULL,
|
||||
"role" "UserRole" NOT NULL DEFAULT 'VISITOR',
|
||||
"avatar" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"bio" TEXT,
|
||||
"location" TEXT,
|
||||
"phone" TEXT,
|
||||
"isSuspended" BOOLEAN NOT NULL DEFAULT false,
|
||||
"suspensionReason" TEXT,
|
||||
"countryId" TEXT,
|
||||
"resetToken" TEXT,
|
||||
"resetTokenExpiry" TIMESTAMP(3),
|
||||
"emailVerified" BOOLEAN NOT NULL DEFAULT false,
|
||||
"verificationToken" TEXT,
|
||||
|
||||
CONSTRAINT "User_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Business" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"category" TEXT NOT NULL,
|
||||
"location" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"logoUrl" TEXT NOT NULL,
|
||||
"videoUrl" TEXT,
|
||||
"contactEmail" TEXT NOT NULL,
|
||||
"contactPhone" TEXT,
|
||||
"socialLinks" JSONB,
|
||||
"verified" BOOLEAN NOT NULL DEFAULT false,
|
||||
"viewCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"rating" DOUBLE PRECISION NOT NULL DEFAULT 0.0,
|
||||
"ratingCount" INTEGER NOT NULL DEFAULT 0,
|
||||
"tags" TEXT[],
|
||||
"isFeatured" BOOLEAN NOT NULL DEFAULT false,
|
||||
"founderName" TEXT,
|
||||
"founderImageUrl" TEXT,
|
||||
"keyMetric" TEXT,
|
||||
"ownerId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"slug" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT false,
|
||||
"showEmail" BOOLEAN NOT NULL DEFAULT true,
|
||||
"showPhone" BOOLEAN NOT NULL DEFAULT true,
|
||||
"showSocials" BOOLEAN NOT NULL DEFAULT true,
|
||||
"websiteUrl" TEXT,
|
||||
"isSuspended" BOOLEAN NOT NULL DEFAULT false,
|
||||
"suspensionReason" TEXT,
|
||||
"plan" "Plan" NOT NULL DEFAULT 'STARTER',
|
||||
"city" TEXT,
|
||||
"countryId" TEXT,
|
||||
"coverUrl" TEXT,
|
||||
"coverPosition" TEXT DEFAULT '50% 50%',
|
||||
"coverZoom" DOUBLE PRECISION DEFAULT 1.0,
|
||||
"suggestedCategory" TEXT,
|
||||
"categoryId" TEXT,
|
||||
|
||||
CONSTRAINT "Business_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "BusinessCategory" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"slug" TEXT NOT NULL,
|
||||
"icon" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "BusinessCategory_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Country" (
|
||||
"id" TEXT NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"code" TEXT NOT NULL,
|
||||
"flag" TEXT,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"description" TEXT,
|
||||
|
||||
CONSTRAINT "Country_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "PricingPlan" (
|
||||
"id" TEXT NOT NULL,
|
||||
"tier" "Plan" NOT NULL,
|
||||
"name" TEXT NOT NULL,
|
||||
"priceXOF" TEXT NOT NULL,
|
||||
"priceEUR" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"features" TEXT[],
|
||||
"offerLimit" INTEGER NOT NULL DEFAULT 1,
|
||||
"recommended" BOOLEAN NOT NULL DEFAULT false,
|
||||
"color" TEXT NOT NULL DEFAULT 'gray',
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"yearlyPriceEUR" TEXT,
|
||||
"yearlyPriceXOF" TEXT,
|
||||
|
||||
CONSTRAINT "PricingPlan_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Offer" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"type" "OfferType" NOT NULL,
|
||||
"price" DOUBLE PRECISION NOT NULL,
|
||||
"currency" TEXT NOT NULL DEFAULT 'XOF',
|
||||
"description" TEXT,
|
||||
"imageUrl" TEXT NOT NULL,
|
||||
"active" BOOLEAN NOT NULL DEFAULT true,
|
||||
"businessId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Offer_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "BlogPost" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"excerpt" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"author" TEXT NOT NULL,
|
||||
"date" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"imageUrl" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"metaDescription" TEXT,
|
||||
"metaTitle" TEXT,
|
||||
"slug" TEXT,
|
||||
"tags" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||
|
||||
CONSTRAINT "BlogPost_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Interview" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"guestName" TEXT NOT NULL,
|
||||
"companyName" TEXT NOT NULL,
|
||||
"role" TEXT NOT NULL,
|
||||
"type" "InterviewType" NOT NULL,
|
||||
"thumbnailUrl" TEXT NOT NULL,
|
||||
"videoUrl" TEXT,
|
||||
"content" TEXT,
|
||||
"excerpt" TEXT NOT NULL,
|
||||
"date" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"duration" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"metaDescription" TEXT,
|
||||
"metaTitle" TEXT,
|
||||
"slug" TEXT,
|
||||
"tags" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||
|
||||
CONSTRAINT "Interview_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Comment" (
|
||||
"id" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"authorId" TEXT NOT NULL,
|
||||
"businessId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Comment_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "AnalyticsEvent" (
|
||||
"id" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"path" TEXT NOT NULL,
|
||||
"label" TEXT,
|
||||
"value" DOUBLE PRECISION,
|
||||
"metadata" JSONB,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"browser" TEXT,
|
||||
"city" TEXT,
|
||||
"country" TEXT,
|
||||
"device" TEXT,
|
||||
"ip" TEXT,
|
||||
"os" TEXT,
|
||||
"referrer" TEXT,
|
||||
"userId" TEXT,
|
||||
|
||||
CONSTRAINT "AnalyticsEvent_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Rating" (
|
||||
"id" TEXT NOT NULL,
|
||||
"value" INTEGER NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"businessId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"comment" TEXT,
|
||||
"reply" TEXT,
|
||||
"replyAt" TIMESTAMP(3),
|
||||
"status" "RatingStatus" NOT NULL DEFAULT 'PENDING',
|
||||
|
||||
CONSTRAINT "Rating_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Conversation" (
|
||||
"id" TEXT NOT NULL,
|
||||
"businessId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "Conversation_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "ConversationParticipant" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"conversationId" TEXT NOT NULL,
|
||||
"isArchived" BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
CONSTRAINT "ConversationParticipant_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Message" (
|
||||
"id" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"senderId" TEXT NOT NULL,
|
||||
"conversationId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"read" BOOLEAN NOT NULL DEFAULT false,
|
||||
|
||||
CONSTRAINT "Message_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "MessageReport" (
|
||||
"id" TEXT NOT NULL,
|
||||
"reason" TEXT,
|
||||
"messageId" TEXT NOT NULL,
|
||||
"reporterId" TEXT NOT NULL,
|
||||
"status" "ReportStatus" NOT NULL DEFAULT 'PENDING',
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "MessageReport_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "SiteSetting" (
|
||||
"id" TEXT NOT NULL DEFAULT 'singleton',
|
||||
"siteName" TEXT NOT NULL DEFAULT 'Afrohub',
|
||||
"siteSlogan" TEXT NOT NULL DEFAULT 'La plateforme de référence pour l''entrepreneuriat africain.',
|
||||
"contactEmail" TEXT NOT NULL DEFAULT 'support@afrohub.com',
|
||||
"contactPhone" TEXT DEFAULT '+225 00 00 00 00 00',
|
||||
"address" TEXT DEFAULT 'Abidjan, Côte d''Ivoire',
|
||||
"facebookUrl" TEXT,
|
||||
"twitterUrl" TEXT,
|
||||
"instagramUrl" TEXT,
|
||||
"linkedinUrl" TEXT,
|
||||
"footerText" TEXT DEFAULT '© 2025 Afrohub. Tous droits réservés.',
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"homeBlogCount" INTEGER NOT NULL DEFAULT 3,
|
||||
"homeBlogShow" BOOLEAN NOT NULL DEFAULT true,
|
||||
"homeBlogSubtitle" TEXT NOT NULL DEFAULT 'Toutes les actualités de l''entrepreneuriat africain.',
|
||||
"homeBlogTitle" TEXT NOT NULL DEFAULT 'Derniers Articles',
|
||||
"homeBlogCategories" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||
"homeBlogIds" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||
"homeBlogSelection" TEXT NOT NULL DEFAULT 'latest',
|
||||
"homeCategories" TEXT[] DEFAULT ARRAY['Technologie & IT', 'Agriculture & Agrobusiness', 'Mode & Textile', 'Cosmétique & Beauté']::TEXT[],
|
||||
"resetPasswordSubject" TEXT NOT NULL DEFAULT 'Réinitialisation de votre mot de passe - Afrohub',
|
||||
"resetPasswordTemplate" TEXT NOT NULL DEFAULT '<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px;"><h2 style="color: #0d9488; text-align: center;">{siteName}</h2><p>Bonjour {name},</p><p>Vous avez demandé la réinitialisation de votre mot de passe. Cliquez sur le bouton ci-dessous pour choisir un nouveau mot de passe :</p><div style="text-align: center; margin: 30px 0;"><a href="{resetUrl}" style="background-color: #0d9488; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; font-weight: bold;">Réinitialiser mon mot de passe</a></div><p>Ce lien expirera dans 1 heure. Si vous n''avez pas demandé cette réinitialisation, vous pouvez ignorer cet email.</p><hr style="border: 0; border-top: 1px solid #e5e7eb; margin: 20px 0;"><p style="font-size: 12px; color: #6b7280; text-align: center;">© 2025 {siteName}. Tous droits réservés.</p></div>',
|
||||
"verifyEmailSubject" TEXT NOT NULL DEFAULT 'Vérification de votre compte - Afrohub',
|
||||
"verifyEmailTemplate" TEXT NOT NULL DEFAULT '<div style="font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px;"><h2 style="color: #0d9488; text-align: center;">{siteName}</h2><p>Bonjour {name},</p><p>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 :</p><div style="text-align: center; margin: 30px 0;"><a href="{verifyUrl}" style="background-color: #0d9488; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; font-weight: bold;">Vérifier mon compte</a></div><p>Si vous n''avez pas créé de compte sur notre plateforme, vous pouvez ignorer cet email.</p><hr style="border: 0; border-top: 1px solid #e5e7eb; margin: 20px 0;"><p style="font-size: 12px; color: #6b7280; text-align: center;">© 2025 {siteName}. Tous droits réservés.</p></div>',
|
||||
|
||||
CONSTRAINT "SiteSetting_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "LegalDocument" (
|
||||
"id" TEXT NOT NULL,
|
||||
"type" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"content" TEXT NOT NULL,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
|
||||
CONSTRAINT "LegalDocument_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Event" (
|
||||
"id" TEXT NOT NULL,
|
||||
"title" TEXT NOT NULL,
|
||||
"description" TEXT NOT NULL,
|
||||
"date" TIMESTAMP(3) NOT NULL,
|
||||
"location" TEXT NOT NULL,
|
||||
"thumbnailUrl" TEXT NOT NULL,
|
||||
"link" TEXT,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" TIMESTAMP(3) NOT NULL,
|
||||
"metaDescription" TEXT,
|
||||
"metaTitle" TEXT,
|
||||
"slug" TEXT,
|
||||
"tags" TEXT[] DEFAULT ARRAY[]::TEXT[],
|
||||
|
||||
CONSTRAINT "Event_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "Favorite" (
|
||||
"id" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"businessId" TEXT NOT NULL,
|
||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
|
||||
CONSTRAINT "Favorite_pkey" PRIMARY KEY ("id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_email_key" ON "User"("email");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_resetToken_key" ON "User"("resetToken");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "User_verificationToken_key" ON "User"("verificationToken");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Business_ownerId_key" ON "Business"("ownerId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Business_slug_key" ON "Business"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "BusinessCategory_name_key" ON "BusinessCategory"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "BusinessCategory_slug_key" ON "BusinessCategory"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Country_name_key" ON "Country"("name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Country_code_key" ON "Country"("code");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "PricingPlan_tier_key" ON "PricingPlan"("tier");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "BlogPost_slug_key" ON "BlogPost"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Interview_slug_key" ON "Interview"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Rating_userId_businessId_key" ON "Rating"("userId", "businessId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "ConversationParticipant_userId_conversationId_key" ON "ConversationParticipant"("userId", "conversationId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "LegalDocument_type_key" ON "LegalDocument"("type");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Event_slug_key" ON "Event"("slug");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "Favorite_userId_businessId_key" ON "Favorite"("userId", "businessId");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "User" ADD CONSTRAINT "User_countryId_fkey" FOREIGN KEY ("countryId") REFERENCES "Country"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Business" ADD CONSTRAINT "Business_categoryId_fkey" FOREIGN KEY ("categoryId") REFERENCES "BusinessCategory"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Business" ADD CONSTRAINT "Business_countryId_fkey" FOREIGN KEY ("countryId") REFERENCES "Country"("id") ON DELETE SET NULL ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Business" ADD CONSTRAINT "Business_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Offer" ADD CONSTRAINT "Offer_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Comment" ADD CONSTRAINT "Comment_authorId_fkey" FOREIGN KEY ("authorId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Comment" ADD CONSTRAINT "Comment_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Rating" ADD CONSTRAINT "Rating_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Rating" ADD CONSTRAINT "Rating_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Conversation" ADD CONSTRAINT "Conversation_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ConversationParticipant" ADD CONSTRAINT "ConversationParticipant_conversationId_fkey" FOREIGN KEY ("conversationId") REFERENCES "Conversation"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "ConversationParticipant" ADD CONSTRAINT "ConversationParticipant_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Message" ADD CONSTRAINT "Message_conversationId_fkey" FOREIGN KEY ("conversationId") REFERENCES "Conversation"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Message" ADD CONSTRAINT "Message_senderId_fkey" FOREIGN KEY ("senderId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "MessageReport" ADD CONSTRAINT "MessageReport_messageId_fkey" FOREIGN KEY ("messageId") REFERENCES "Message"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "MessageReport" ADD CONSTRAINT "MessageReport_reporterId_fkey" FOREIGN KEY ("reporterId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Favorite" ADD CONSTRAINT "Favorite_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "Favorite" ADD CONSTRAINT "Favorite_businessId_fkey" FOREIGN KEY ("businessId") REFERENCES "Business"("id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
@@ -1,8 +0,0 @@
|
||||
-- AlterTable
|
||||
ALTER TABLE "BlogPost" ADD COLUMN "publishedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Event" ADD COLUMN "publishedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Interview" ADD COLUMN "publishedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP;
|
||||
@@ -1,11 +0,0 @@
|
||||
-- CreateEnum
|
||||
CREATE TYPE "ContentStatus" AS ENUM ('DRAFT', 'PUBLISHED', 'ARCHIVED');
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "BlogPost" ADD COLUMN "status" "ContentStatus" NOT NULL DEFAULT 'PUBLISHED';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Event" ADD COLUMN "status" "ContentStatus" NOT NULL DEFAULT 'PUBLISHED';
|
||||
|
||||
-- AlterTable
|
||||
ALTER TABLE "Interview" ADD COLUMN "status" "ContentStatus" NOT NULL DEFAULT 'PUBLISHED';
|
||||
@@ -1,3 +0,0 @@
|
||||
# Please do not edit this file manually
|
||||
# It should be added in your version-control system (e.g., Git)
|
||||
provider = "postgresql"
|
||||
@@ -1,426 +0,0 @@
|
||||
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?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
bio String?
|
||||
location String?
|
||||
phone String?
|
||||
isSuspended Boolean @default(false)
|
||||
suspensionReason String?
|
||||
countryId String?
|
||||
resetToken String? @unique
|
||||
resetTokenExpiry DateTime?
|
||||
emailVerified Boolean @default(false)
|
||||
verificationToken String? @unique
|
||||
businesses Business?
|
||||
comments Comment[]
|
||||
conversations ConversationParticipant[]
|
||||
favorites Favorite[]
|
||||
sentMessages Message[]
|
||||
reports MessageReport[]
|
||||
ratings Rating[]
|
||||
country Country? @relation(fields: [countryId], references: [id])
|
||||
}
|
||||
|
||||
model Business {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
category String
|
||||
location String
|
||||
description String
|
||||
logoUrl String
|
||||
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)
|
||||
city String?
|
||||
countryId String?
|
||||
coverUrl String?
|
||||
coverPosition String? @default("50% 50%")
|
||||
coverZoom Float? @default(1.0)
|
||||
suggestedCategory String?
|
||||
categoryId String?
|
||||
metaDescription String?
|
||||
metaTitle String?
|
||||
categoryRef BusinessCategory? @relation(fields: [categoryId], references: [id])
|
||||
country Country? @relation(fields: [countryId], references: [id])
|
||||
owner User @relation(fields: [ownerId], references: [id])
|
||||
comments Comment[]
|
||||
conversations Conversation[]
|
||||
favorites Favorite[]
|
||||
homeSlides HomeSlide[]
|
||||
offers Offer[]
|
||||
ratings Rating[]
|
||||
}
|
||||
|
||||
model BusinessCategory {
|
||||
id String @id @default(uuid())
|
||||
name String @unique
|
||||
slug String @unique
|
||||
icon String?
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
businesses Business[]
|
||||
}
|
||||
|
||||
model Country {
|
||||
id String @id @default(uuid())
|
||||
name String @unique
|
||||
code String @unique
|
||||
flag String?
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
description String?
|
||||
businesses Business[]
|
||||
users User[]
|
||||
}
|
||||
|
||||
model PricingPlan {
|
||||
id String @id @default(uuid())
|
||||
tier Plan @unique
|
||||
name String
|
||||
priceXOF String
|
||||
priceEUR String
|
||||
description String
|
||||
features String[]
|
||||
offerLimit Int @default(1)
|
||||
recommended Boolean @default(false)
|
||||
color String @default("gray")
|
||||
updatedAt DateTime @updatedAt
|
||||
yearlyPriceEUR String?
|
||||
yearlyPriceXOF String?
|
||||
}
|
||||
|
||||
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
|
||||
excerpt String
|
||||
content String
|
||||
author String
|
||||
date DateTime @default(now())
|
||||
imageUrl String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
metaDescription String?
|
||||
metaTitle String?
|
||||
slug String? @unique
|
||||
tags String[] @default([])
|
||||
publishedAt DateTime @default(now())
|
||||
status ContentStatus @default(PUBLISHED)
|
||||
coverPosition String? @default("50% 50%")
|
||||
coverZoom Float? @default(1.0)
|
||||
}
|
||||
|
||||
model HomeSlide {
|
||||
id String @id @default(uuid())
|
||||
type HomeSlideType @default(CUSTOM)
|
||||
businessId String?
|
||||
title String?
|
||||
subtitle String?
|
||||
imageUrl String?
|
||||
linkUrl String?
|
||||
order Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
coverPosition String? @default("50% 50%")
|
||||
coverZoom Float? @default(1.0)
|
||||
business Business? @relation(fields: [businessId], references: [id])
|
||||
}
|
||||
|
||||
model Interview {
|
||||
id String @id @default(uuid())
|
||||
title String
|
||||
guestName String
|
||||
companyName String
|
||||
role String
|
||||
type InterviewType
|
||||
thumbnailUrl String
|
||||
videoUrl String?
|
||||
content String?
|
||||
excerpt String
|
||||
date DateTime @default(now())
|
||||
duration String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
metaDescription String?
|
||||
metaTitle String?
|
||||
slug String? @unique
|
||||
tags String[] @default([])
|
||||
publishedAt DateTime @default(now())
|
||||
status ContentStatus @default(PUBLISHED)
|
||||
coverPosition String? @default("50% 50%")
|
||||
coverZoom Float? @default(1.0)
|
||||
}
|
||||
|
||||
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?
|
||||
createdAt DateTime @default(now())
|
||||
browser String?
|
||||
city String?
|
||||
country String?
|
||||
device String?
|
||||
ip String?
|
||||
os String?
|
||||
referrer String?
|
||||
userId String?
|
||||
}
|
||||
|
||||
model Rating {
|
||||
id String @id @default(uuid())
|
||||
value Int
|
||||
userId String
|
||||
businessId String
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
comment String?
|
||||
reply String?
|
||||
replyAt DateTime?
|
||||
status RatingStatus @default(PENDING)
|
||||
business Business @relation(fields: [businessId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, businessId])
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
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.")
|
||||
updatedAt DateTime @updatedAt
|
||||
homeBlogCount Int @default(3)
|
||||
homeBlogShow Boolean @default(true)
|
||||
homeBlogSubtitle String @default("Toutes les actualités de l'entrepreneuriat africain.")
|
||||
homeBlogTitle String @default("Derniers Articles")
|
||||
homeBlogCategories String[] @default([])
|
||||
homeBlogIds String[] @default([])
|
||||
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("<div style=\"font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px;\"><h2 style=\"color: #0d9488; text-align: center;\">{siteName}</h2><p>Bonjour {name},</p><p>Vous avez demandé la réinitialisation de votre mot de passe. Cliquez sur le bouton ci-dessous pour choisir un nouveau mot de passe :</p><div style=\"text-align: center; margin: 30px 0;\"><a href=\"{resetUrl}\" style=\"background-color: #0d9488; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; font-weight: bold;\">Réinitialiser mon mot de passe</a></div><p>Ce lien expirera dans 1 heure. Si vous n'avez pas demandé cette réinitialisation, vous pouvez ignorer cet email.</p><hr style=\"border: 0; border-top: 1px solid #e5e7eb; margin: 20px 0;\"><p style=\"font-size: 12px; color: #6b7280; text-align: center;\">© 2025 {siteName}. Tous droits réservés.</p></div>")
|
||||
verifyEmailSubject String @default("Vérification de votre compte - Afrohub")
|
||||
verifyEmailTemplate String @default("<div style=\"font-family: sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #e5e7eb; border-radius: 8px;\"><h2 style=\"color: #0d9488; text-align: center;\">{siteName}</h2><p>Bonjour {name},</p><p>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 :</p><div style=\"text-align: center; margin: 30px 0;\"><a href=\"{verifyUrl}\" style=\"background-color: #0d9488; color: white; padding: 12px 24px; text-decoration: none; border-radius: 6px; font-weight: bold;\">Vérifier mon compte</a></div><p>Si vous n'avez pas créé de compte sur notre plateforme, vous pouvez ignorer cet email.</p><hr style=\"border: 0; border-top: 1px solid #e5e7eb; margin: 20px 0;\"><p style=\"font-size: 12px; color: #6b7280; text-align: center;\">© 2025 {siteName}. Tous droits réservés.</p></div>")
|
||||
}
|
||||
|
||||
model OneShotPlan {
|
||||
id String @id @default(uuid())
|
||||
type OneShotType @unique
|
||||
name String
|
||||
priceXOF Int @default(0)
|
||||
priceEUR Int @default(0)
|
||||
description String?
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
enum OneShotType {
|
||||
BUMP
|
||||
POST_EVENT
|
||||
POST_NEWS
|
||||
AD_DIRECTORY
|
||||
}
|
||||
|
||||
model LegalDocument {
|
||||
id String @id @default(uuid())
|
||||
type String @unique
|
||||
title String
|
||||
content String
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
model Event {
|
||||
id String @id @default(uuid())
|
||||
title String
|
||||
description String
|
||||
date DateTime
|
||||
location String
|
||||
thumbnailUrl String
|
||||
link String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
metaDescription String?
|
||||
metaTitle String?
|
||||
slug String? @unique
|
||||
tags String[] @default([])
|
||||
publishedAt DateTime @default(now())
|
||||
status ContentStatus @default(PUBLISHED)
|
||||
coverPosition String? @default("50% 50%")
|
||||
coverZoom Float? @default(1.0)
|
||||
}
|
||||
|
||||
model Favorite {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
businessId String
|
||||
createdAt DateTime @default(now())
|
||||
business Business @relation(fields: [businessId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, businessId])
|
||||
}
|
||||
|
||||
enum HomeSlideType {
|
||||
BUSINESS
|
||||
CUSTOM
|
||||
}
|
||||
|
||||
enum ContentStatus {
|
||||
DRAFT
|
||||
PENDING
|
||||
PUBLISHED
|
||||
ARCHIVED
|
||||
}
|
||||
|
||||
enum RatingStatus {
|
||||
PENDING
|
||||
APPROVED
|
||||
REJECTED
|
||||
}
|
||||
|
||||
enum ReportStatus {
|
||||
PENDING
|
||||
RESOLVED
|
||||
DISMISSED
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
VISITOR
|
||||
ENTREPRENEUR
|
||||
ADMIN
|
||||
}
|
||||
|
||||
enum Plan {
|
||||
STARTER
|
||||
BOOSTER
|
||||
EMPIRE
|
||||
}
|
||||
|
||||
enum OfferType {
|
||||
PRODUCT
|
||||
SERVICE
|
||||
}
|
||||
|
||||
enum InterviewType {
|
||||
VIDEO
|
||||
ARTICLE
|
||||
}
|
||||
@@ -11,8 +11,8 @@
|
||||
"dev:admin": "npm run dev --prefix admin -- -p 3001",
|
||||
"all": "concurrently \"npm run dev\" \"npm run dev:admin\"",
|
||||
"build": "prisma generate && next build && npm run build:admin",
|
||||
"build:admin": "npm install --prefix admin --legacy-peer-deps && prisma generate && npm run build --prefix admin",
|
||||
"generate": "npx prisma generate && cd admin && npx prisma generate && cd ..",
|
||||
"build:admin": "npm install --prefix admin --legacy-peer-deps && npm run build --prefix admin",
|
||||
"generate": "npx prisma generate && cd admin && npx prisma generate --schema=../prisma/schema.prisma && cd ..",
|
||||
"start": "npx prisma migrate deploy && next start",
|
||||
"start:admin": "npm run start --prefix admin",
|
||||
"db:migrate": "prisma migrate dev",
|
||||
|
||||
Reference in New Issue
Block a user