Suspend / Reactivate / Ban buttons on the user detail page; wired to spoke endpoints (sase.tr#27). Admin SDK - suspendUser/reactivateUser/banUser on SaseAdmin + LifecycleResult. - SASE_ADMIN_ENDPOINTS updated. Route - POST /api/sase/users/[id]/lifecycle (action + reason). Auth + spoke wired + min reason length checks. Audit on both success and failure. RO model - Sase Prisma schema adds status/statusReason/statusChangedAt/ statusChangedBy. getUser() returns lifecycleStatus + statusReason. UI - LifecycleStatusBadge in header next to email reveal. - LifecycleButtons renders the right actions for the current state. - Modals with reason textarea; ban requires a double-confirm checkbox. - Impersonate hidden when user is suspended/banned (AuthGuard rejects). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
170 lines
6.6 KiB
Plaintext
170 lines
6.6 KiB
Plaintext
// Partial view of Sase.tr public schema.
|
|
// Owned by the spoke; panel reads with super_panel_reader (SELECT only).
|
|
// Add models here only as panel features need them — keep the surface narrow.
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
output = "../../node_modules/.prisma/client-sase"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL_SASE_RO")
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
name String @db.VarChar(255)
|
|
email String @unique @db.VarChar(255)
|
|
emailVerified Boolean @default(false) @map("email_verified")
|
|
role String @default("user") @db.VarChar(20)
|
|
status String @default("active") @db.VarChar(20)
|
|
statusReason String? @map("status_reason")
|
|
statusChangedAt DateTime? @map("status_changed_at") @db.Timestamptz(6)
|
|
statusChangedBy String? @map("status_changed_by") @db.Uuid
|
|
image String?
|
|
referralCode String? @map("referral_code") @db.VarChar(20)
|
|
referredBy String? @map("referred_by") @db.Uuid
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz(6)
|
|
|
|
subscriptions UserSubscription[]
|
|
payments Payment[]
|
|
brands UserBrand[]
|
|
queryLogs QueryLog[]
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
model Plan {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
name String @db.VarChar(100)
|
|
brandCount Int @map("brand_count")
|
|
priceMonthly Int @map("price_monthly")
|
|
priceYearly Int @map("price_yearly")
|
|
isActive Boolean @default(true) @map("is_active")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz(6)
|
|
|
|
subscriptions UserSubscription[]
|
|
|
|
@@map("plans")
|
|
}
|
|
|
|
model UserSubscription {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
planId String @map("plan_id") @db.Uuid
|
|
status String @default("pending") @db.VarChar(20)
|
|
billingPeriod String @default("monthly") @map("billing_period") @db.VarChar(10)
|
|
startDate DateTime? @map("start_date") @db.Timestamptz(6)
|
|
endDate DateTime? @map("end_date") @db.Timestamptz(6)
|
|
cancelledAt DateTime? @map("cancelled_at") @db.Timestamptz(6)
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz(6)
|
|
|
|
user User @relation(fields: [userId], references: [id])
|
|
plan Plan @relation(fields: [planId], references: [id])
|
|
brands UserBrand[]
|
|
payments Payment[]
|
|
|
|
@@index([status])
|
|
@@index([userId])
|
|
@@map("user_subscriptions")
|
|
}
|
|
|
|
model Brand {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
name String @db.VarChar(100)
|
|
slug String @unique @db.VarChar(100)
|
|
logoUrl String? @map("logo_url")
|
|
isActive Boolean @default(true) @map("is_active")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz(6)
|
|
|
|
users UserBrand[]
|
|
|
|
@@map("brands")
|
|
}
|
|
|
|
model UserBrand {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
subscriptionId String @map("subscription_id") @db.Uuid
|
|
brandId String @map("brand_id") @db.Uuid
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
user User @relation(fields: [userId], references: [id])
|
|
subscription UserSubscription @relation(fields: [subscriptionId], references: [id])
|
|
brand Brand @relation(fields: [brandId], references: [id])
|
|
|
|
@@unique([userId, subscriptionId, brandId])
|
|
@@index([userId])
|
|
@@map("user_brands")
|
|
}
|
|
|
|
model BankAccount {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
bankName String @map("bank_name") @db.VarChar(100)
|
|
accountHolder String @map("account_holder") @db.VarChar(200)
|
|
iban String @db.VarChar(34)
|
|
kolayAdres String? @map("kolay_adres") @db.VarChar(100)
|
|
kolayAdresType String? @map("kolay_adres_type") @db.VarChar(20)
|
|
qrImageUrl String? @map("qr_image_url")
|
|
descriptionTemplate String @default("SASE-{{paymentId}}") @map("description_template") @db.VarChar(200)
|
|
isActive Boolean @default(false) @map("is_active")
|
|
displayOrder Int @default(0) @map("display_order")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz(6)
|
|
|
|
payments Payment[]
|
|
|
|
@@map("bank_accounts")
|
|
}
|
|
|
|
model Payment {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
subscriptionId String @map("subscription_id") @db.Uuid
|
|
amount Int
|
|
currency String @default("TRY") @db.VarChar(3)
|
|
method String @db.VarChar(20)
|
|
status String @default("pending") @db.VarChar(20)
|
|
iyzicoPaymentId String? @map("iyzico_payment_id")
|
|
stripeSessionId String? @map("stripe_session_id")
|
|
stripePaymentIntentId String? @map("stripe_payment_intent_id")
|
|
bankAccountId String? @map("bank_account_id") @db.Uuid
|
|
eftReceiptUrl String? @map("eft_receipt_url")
|
|
adminNote String? @map("admin_note")
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
updatedAt DateTime @default(now()) @map("updated_at") @db.Timestamptz(6)
|
|
|
|
user User @relation(fields: [userId], references: [id])
|
|
subscription UserSubscription @relation(fields: [subscriptionId], references: [id])
|
|
bankAccount BankAccount? @relation(fields: [bankAccountId], references: [id])
|
|
|
|
@@index([userId])
|
|
@@index([status])
|
|
@@index([stripeSessionId])
|
|
@@map("payments")
|
|
}
|
|
|
|
model QueryLog {
|
|
id String @id @default(uuid()) @db.Uuid
|
|
userId String @map("user_id") @db.Uuid
|
|
vin String @db.VarChar(17)
|
|
brandId String? @map("brand_id") @db.Uuid
|
|
source String? @db.VarChar(20)
|
|
success Boolean @default(true)
|
|
errorMessage String? @map("error_message")
|
|
responseTimeMs Int? @map("response_time_ms")
|
|
timings Json?
|
|
createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz(6)
|
|
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
@@index([userId, createdAt])
|
|
@@index([vin])
|
|
@@map("query_logs")
|
|
}
|