Files
sp/apps/web/prisma/sase/schema.prisma
Semih b1ec7a5277 feat(sase): user lifecycle controls — Phase B
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>
2026-05-18 09:38:07 +03:00

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")
}