2026-02-10 15:44:35 +05:30
|
|
|
// 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")
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===== ENUMS =====
|
|
|
|
|
|
|
|
|
|
enum CampaignStatus {
|
|
|
|
|
DRAFT
|
|
|
|
|
IN_REVIEW
|
|
|
|
|
ACTIVE
|
|
|
|
|
PAUSED
|
|
|
|
|
ENDED
|
|
|
|
|
REJECTED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum BillingModel {
|
|
|
|
|
FIXED
|
|
|
|
|
CPM
|
|
|
|
|
CPC
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum CampaignObjective {
|
|
|
|
|
AWARENESS
|
|
|
|
|
SALES
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum SurfaceKey {
|
|
|
|
|
HOME_FEATURED_CAROUSEL
|
|
|
|
|
HOME_TOP_EVENTS
|
|
|
|
|
CATEGORY_FEATURED
|
|
|
|
|
CITY_TRENDING
|
|
|
|
|
SEARCH_BOOSTED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum TrackingEventType {
|
|
|
|
|
IMPRESSION
|
|
|
|
|
CLICK
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ===== MODELS =====
|
|
|
|
|
|
|
|
|
|
model Campaign {
|
|
|
|
|
id String @id @default(uuid())
|
|
|
|
|
partnerId String
|
|
|
|
|
name String
|
|
|
|
|
objective CampaignObjective
|
|
|
|
|
status CampaignStatus @default(DRAFT)
|
|
|
|
|
|
|
|
|
|
startAt DateTime
|
|
|
|
|
endAt DateTime
|
|
|
|
|
|
|
|
|
|
billingModel BillingModel
|
|
|
|
|
totalBudget Decimal @db.Decimal(10, 2)
|
|
|
|
|
dailyCap Decimal? @db.Decimal(10, 2)
|
|
|
|
|
spent Decimal @default(0) @db.Decimal(10, 2)
|
|
|
|
|
|
|
|
|
|
// Targeting (stored as JSON)
|
|
|
|
|
targeting Json // { cityIds: [], categoryIds: [], countryCodes: [] }
|
|
|
|
|
frequencyCap Int @default(0) // 0 = unlimited
|
|
|
|
|
|
|
|
|
|
// Relations
|
|
|
|
|
placements SponsoredPlacement[]
|
|
|
|
|
events CampaignEvent[] // Many-to-many via join table or array of IDs
|
|
|
|
|
|
|
|
|
|
approvedBy String?
|
|
|
|
|
rejectedReason String?
|
|
|
|
|
createdBy String
|
|
|
|
|
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
auditLogs CampaignAuditLog[]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model SponsoredPlacement {
|
|
|
|
|
id String @id @default(uuid())
|
|
|
|
|
campaignId String
|
|
|
|
|
campaign Campaign @relation(fields: [campaignId], references: [id])
|
|
|
|
|
|
|
|
|
|
eventId String
|
|
|
|
|
surfaceKey SurfaceKey
|
|
|
|
|
priority String @default("SPONSORED")
|
|
|
|
|
|
|
|
|
|
bid Decimal @db.Decimal(10, 2)
|
|
|
|
|
status String @default("ACTIVE") // ACTIVE, PAUSED
|
|
|
|
|
rank Int @default(0)
|
|
|
|
|
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@unique([campaignId, eventId, surfaceKey])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model CampaignEvent {
|
|
|
|
|
id String @id @default(uuid())
|
|
|
|
|
campaignId String
|
|
|
|
|
campaign Campaign @relation(fields: [campaignId], references: [id])
|
|
|
|
|
eventId String // Reference to Event table (not shown here)
|
|
|
|
|
|
|
|
|
|
@@unique([campaignId, eventId])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model AdTrackingEvent {
|
|
|
|
|
id String @id @default(uuid())
|
|
|
|
|
type TrackingEventType
|
|
|
|
|
|
|
|
|
|
placementId String
|
|
|
|
|
campaignId String
|
|
|
|
|
surfaceKey SurfaceKey
|
|
|
|
|
eventId String
|
|
|
|
|
|
|
|
|
|
userId String?
|
|
|
|
|
anonId String
|
|
|
|
|
sessionId String
|
|
|
|
|
|
|
|
|
|
timestamp DateTime @default(now())
|
|
|
|
|
device String?
|
|
|
|
|
cityId String?
|
|
|
|
|
|
|
|
|
|
@@index([campaignId, type, timestamp])
|
|
|
|
|
@@index([anonId, timestamp]) // For frequency capping queries
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model PlacementDailyStats {
|
|
|
|
|
id String @id @default(uuid())
|
|
|
|
|
campaignId String
|
|
|
|
|
placementId String
|
|
|
|
|
surfaceKey SurfaceKey
|
|
|
|
|
|
|
|
|
|
date DateTime @db.Date
|
|
|
|
|
|
|
|
|
|
impressions Int @default(0)
|
|
|
|
|
clicks Int @default(0)
|
|
|
|
|
spend Decimal @default(0) @db.Decimal(10, 2)
|
|
|
|
|
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
|
|
|
|
|
@@unique([campaignId, placementId, surfaceKey, date])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model CampaignAuditLog {
|
|
|
|
|
id String @id @default(uuid())
|
|
|
|
|
campaignId String
|
|
|
|
|
campaign Campaign @relation(fields: [campaignId], references: [id])
|
|
|
|
|
|
|
|
|
|
actorId String
|
|
|
|
|
action String // CREATED, UPDATED, SUBMITTED, APPROVED, REJECTED, PAUSED, RESUMED
|
|
|
|
|
details Json? // Changed fields, reason, etc.
|
|
|
|
|
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
}
|
feat: Partner Command Center Module
- Extend types/partner.ts: riskScore, KYCDocument, PartnerEvent, RiskLevel
- Extend mockPartnerData.ts: risk scores, 15 KYC docs, 9 partner events, 6th partner
- Create lib/actions/partner-governance.ts: KYC verification, event approval, impersonation, 2FA/password reset, suspend/unsuspend
- Rewrite PartnerDirectory.tsx: card grid → data table with stats, risk gauge, filter tabs
- Rewrite PartnerProfile.tsx: tabs → 3-column layout (Identity | KYC Vault | Event Governance)
- Create KYCVaultPanel.tsx: per-doc approve/reject with progress bar and auto-verification
- Create EventApprovalQueue.tsx: pending events list with review dialog
- Create ImpersonationDialog.tsx: audit-aware confirmation with token generation
- Extend prisma/schema.prisma: PartnerProfile, PartnerDoc models, KYC/Event enums
- Add partner governance permission scopes to staff.ts
2026-02-11 10:06:30 +05:30
|
|
|
|
|
|
|
|
// ===== PARTNER GOVERNANCE =====
|
|
|
|
|
|
|
|
|
|
enum KYCStatus {
|
|
|
|
|
PENDING
|
|
|
|
|
VERIFIED
|
|
|
|
|
REJECTED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum KYCDocStatus {
|
|
|
|
|
PENDING
|
|
|
|
|
APPROVED
|
|
|
|
|
REJECTED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
enum PartnerEventStatus {
|
|
|
|
|
PENDING_REVIEW
|
|
|
|
|
LIVE
|
|
|
|
|
DRAFT
|
|
|
|
|
COMPLETED
|
|
|
|
|
CANCELLED
|
|
|
|
|
REJECTED
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model PartnerProfile {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
userId String @unique // FK to User table
|
|
|
|
|
verification KYCStatus @default(PENDING)
|
|
|
|
|
riskScore Int @default(0)
|
|
|
|
|
|
|
|
|
|
documents PartnerDoc[]
|
|
|
|
|
|
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
|
updatedAt DateTime @updatedAt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
model PartnerDoc {
|
|
|
|
|
id String @id @default(cuid())
|
|
|
|
|
partnerId String
|
|
|
|
|
partner PartnerProfile @relation(fields: [partnerId], references: [id])
|
|
|
|
|
|
|
|
|
|
type String // "PAN", "GST", "AADHAAR", "CANCELLED_CHEQUE", "BUSINESS_REG"
|
|
|
|
|
name String
|
|
|
|
|
url String
|
|
|
|
|
status KYCDocStatus @default(PENDING)
|
|
|
|
|
mandatory Boolean @default(true)
|
|
|
|
|
|
|
|
|
|
adminNote String?
|
|
|
|
|
reviewedBy String?
|
|
|
|
|
reviewedAt DateTime?
|
|
|
|
|
|
|
|
|
|
uploadedBy String
|
|
|
|
|
uploadedAt DateTime @default(now())
|
|
|
|
|
|
|
|
|
|
@@index([partnerId, status])
|
|
|
|
|
}
|
|
|
|
|
|