first commit

This commit is contained in:
tusuii
2026-02-19 17:25:38 +05:30
commit 09ea6d4efb
72 changed files with 24296 additions and 0 deletions

384
prisma/schema.prisma Normal file
View File

@@ -0,0 +1,384 @@
// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// User Management & Authentication
model User {
id String @id @default(cuid())
email String @unique
username String? @unique
firstName String?
lastName String?
phone String?
avatar String?
// Authentication
passwordHash String
isVerified Boolean @default(false)
isActive Boolean @default(true)
// Roles & Permissions
role UserRole @default(CUSTOMER)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lastLoginAt DateTime?
// Relations
addresses Address[]
orders Order[]
reviews Review[]
wishlist WishlistItem[]
cart CartItem[]
orderStatusChanges OrderStatusHistory[]
@@map("users")
}
enum UserRole {
CUSTOMER
ADMIN
SUPER_ADMIN
EDITOR
MODERATOR
SELLER
}
// Address Management
model Address {
id String @id @default(cuid())
userId String
type AddressType @default(SHIPPING)
isDefault Boolean @default(false)
// Address Details
firstName String
lastName String
company String?
addressLine1 String
addressLine2 String?
city String
state String
postalCode String
country String
phone String?
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
orders Order[]
@@map("addresses")
}
enum AddressType {
SHIPPING
BILLING
}
// Order Management
model Order {
id String @id @default(cuid())
orderNumber String @unique
userId String
status OrderStatus @default(PENDING)
// Pricing
subtotal Decimal @db.Decimal(10, 2)
taxAmount Decimal @db.Decimal(10, 2)
shippingAmount Decimal @db.Decimal(10, 2)
discountAmount Decimal @db.Decimal(10, 2) @default(0)
totalAmount Decimal @db.Decimal(10, 2)
// Payment
paymentStatus PaymentStatus @default(PENDING)
paymentMethod String?
paymentId String?
// Shipping
shippingAddressId String
trackingNumber String?
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
shippedAt DateTime?
deliveredAt DateTime?
// ✅ Add this field
returnRequestedAt DateTime?
returnStatus ReturnStatus @default(NONE)
// Relations
user User @relation(fields: [userId], references: [id])
address Address @relation(fields: [shippingAddressId], references: [id])
items OrderItem[]
statusHistory OrderStatusHistory[]
@@map("orders")
}
model OrderStatusHistory {
id String @id @default(cuid())
orderId String
fromStatus OrderStatus?
toStatus OrderStatus
changedBy String?
trackingNumber String?
notes String?
ipAddress String?
userAgent String?
createdAt DateTime @default(now())
// Relations
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
admin User? @relation(fields: [changedBy], references: [id])
@@index([orderId])
@@index([createdAt])
@@map("order_status_history")
}
enum OrderStatus {
PENDING
CONFIRMED
PROCESSING
SHIPPED
DELIVERED
CANCELLED
REFUNDED
RETURN_REQUESTED
}
enum PaymentStatus {
PENDING
PAID
FAILED
REFUNDED
PARTIALLY_REFUNDED
}
enum ReturnStatus {
NONE
REQUESTED
APPROVED
REJECTED
COMPLETED
}
// Order Items
model OrderItem {
id String @id @default(cuid())
orderId String
productId String // Reference to MongoDB product
// Product Details (snapshot at time of order)
productName String
productSku String
price Decimal @db.Decimal(10, 2)
quantity Int
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
@@map("order_items")
}
// Reviews & Ratings
model Review {
id String @id @default(cuid())
userId String
productId String // Reference to MongoDB product
orderId String? // Optional reference to order
rating Int // 1-5 stars
title String?
comment String?
isVerified Boolean @default(false)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
user User @relation(fields: [userId], references: [id])
@@unique([userId, productId])
@@map("reviews")
}
// Wishlist Management
model WishlistItem {
id String @id @default(cuid())
userId String
productId String // Reference to MongoDB product
// Timestamps
createdAt DateTime @default(now())
// Relations
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, productId])
@@map("wishlist_items")
}
// Shopping Cart
model CartItem {
id String @id @default(cuid())
userId String
productId String // Reference to MongoDB product
quantity Int @default(1)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([userId, productId])
@@map("cart_items")
}
// Categories (Reference data)
// Categories (Reference data)
model Category {
id String @id @default(cuid())
name String // Removed @unique - same name can exist under different parents
slug String // Removed @unique - will use composite unique instead
description String?
image String?
parentId String?
isActive Boolean @default(true)
sequence Int @default(0)
// SEO
metaTitle String?
metaDescription String?
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
parent Category? @relation("CategoryHierarchy", fields: [parentId], references: [id])
children Category[] @relation("CategoryHierarchy")
// Composite unique constraint: same slug allowed if different parent
@@unique([slug, parentId], name: "unique_slug_per_parent")
@@map("categories")
}
// Coupons & Discounts
model Coupon {
id String @id @default(cuid())
code String @unique
description String?
type CouponType
value Decimal @db.Decimal(10, 2)
// Conditions
minOrderAmount Decimal? @db.Decimal(10, 2)
maxUses Int?
usedCount Int @default(0)
// Validity
validFrom DateTime
validUntil DateTime
isActive Boolean @default(true)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("coupons")
}
enum CouponType {
PERCENTAGE
FIXED_AMOUNT
FREE_SHIPPING
}
// System Configuration
model SystemConfig {
id String @id @default(cuid())
key String @unique
value String
type ConfigType @default(STRING)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("system_config")
}
enum ConfigType {
STRING
NUMBER
BOOLEAN
JSON
}
model InventoryLog {
id String @id @default(cuid())
productId String
productName String
type InventoryLogType
quantityChange Int
previousStock Int
newStock Int
orderId String?
adjustedBy String?
notes String?
createdAt DateTime @default(now())
@@index([productId])
@@index([orderId])
@@index([type])
@@map("inventory_logs")
}
enum InventoryLogType {
SOLD
RESTOCK
ADJUSTMENT
RETURN
DAMAGED
}

174
prisma/seed.js Normal file
View File

@@ -0,0 +1,174 @@
const { PrismaClient } = require('@prisma/client');
const bcrypt = require('bcrypt');
const prisma = new PrismaClient();
async function main() {
console.log('🌱 Starting database seed...');
// Create admin user
const adminPasswordHash = await bcrypt.hash('admin123', 12);
const admin = await prisma.user.upsert({
where: { email: 'admin@vaishnavi.com' },
update: {},
create: {
email: 'admin@vaishnavi.com',
passwordHash: adminPasswordHash,
firstName: 'Admin',
lastName: 'User',
username: 'admin',
role: 'ADMIN',
isVerified: true,
isActive: true,
},
});
// Create test customer
const customerPasswordHash = await bcrypt.hash('customer123', 12);
const customer = await prisma.user.upsert({
where: { email: 'customer@example.com' },
update: {},
create: {
email: 'customer@example.com',
passwordHash: customerPasswordHash,
firstName: 'John',
lastName: 'Doe',
username: 'johndoe',
role: 'CUSTOMER',
isVerified: true,
isActive: true,
},
});
// Create categories
const categories = [
{
name: 'Women\'s Clothing',
slug: 'womens-clothing',
description: 'Beautiful women\'s fashion and apparel',
metaTitle: 'Women\'s Clothing - Vaishnavi Creation',
metaDescription: 'Discover our collection of women\'s clothing and fashion items.',
},
{
name: 'Men\'s Clothing',
slug: 'mens-clothing',
description: 'Stylish men\'s fashion and apparel',
metaTitle: 'Men\'s Clothing - Vaishnavi Creation',
metaDescription: 'Explore our range of men\'s clothing and fashion items.',
},
{
name: 'Accessories',
slug: 'accessories',
description: 'Fashion accessories and jewelry',
metaTitle: 'Accessories - Vaishnavi Creation',
metaDescription: 'Complete your look with our fashion accessories.',
},
{
name: 'Shoes',
slug: 'shoes',
description: 'Comfortable and stylish footwear',
metaTitle: 'Shoes - Vaishnavi Creation',
metaDescription: 'Find the perfect pair of shoes for any occasion.',
},
];
for (const categoryData of categories) {
await prisma.category.upsert({
where: { slug: categoryData.slug },
update: {},
create: categoryData,
});
}
// Create sample coupons
const coupons = [
{
code: 'WELCOME10',
description: '10% off for new customers',
type: 'PERCENTAGE',
value: 10,
minOrderAmount: 50,
maxUses: 1000,
validFrom: new Date(),
validUntil: new Date(Date.now() + 30 * 24 * 60 * 60 * 1000), // 30 days
isActive: true,
},
{
code: 'FREESHIP',
description: 'Free shipping on orders over $100',
type: 'FREE_SHIPPING',
value: 0,
minOrderAmount: 100,
maxUses: null,
validFrom: new Date(),
validUntil: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000), // 90 days
isActive: true,
},
];
for (const couponData of coupons) {
await prisma.coupon.upsert({
where: { code: couponData.code },
update: {},
create: couponData,
});
}
// Create system configuration
const systemConfigs = [
{
key: 'site_name',
value: 'Vaishnavi Creation',
type: 'STRING',
},
{
key: 'site_description',
value: 'Your premier destination for fashion and style',
type: 'STRING',
},
{
key: 'currency',
value: 'USD',
type: 'STRING',
},
{
key: 'tax_rate',
value: '10',
type: 'NUMBER',
},
{
key: 'free_shipping_threshold',
value: '100',
type: 'NUMBER',
},
{
key: 'maintenance_mode',
value: 'false',
type: 'BOOLEAN',
},
];
for (const configData of systemConfigs) {
await prisma.systemConfig.upsert({
where: { key: configData.key },
update: {},
create: configData,
});
}
console.log('✅ Database seeded successfully!');
console.log(`👤 Admin user created: admin@vaishnavi.com / admin123`);
console.log(`👤 Customer user created: customer@example.com / customer123`);
console.log(`📦 ${categories.length} categories created`);
console.log(`🎫 ${coupons.length} coupons created`);
console.log(`⚙️ ${systemConfigs.length} system configs created`);
}
main()
.catch((e) => {
console.error('❌ Seed failed:', e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});