- Add admin-next/: full Next.js + Prisma + shadcn admin panel (45 API routes, 76 components) - docker-compose: tg_shop_admin service (port 3000, shared db/shop.db, prisma), bot talks to it via ADMIN_CHAT_URL=http://tg_shop_admin:3000/api/chat - tor-proxy now proxies onion admin to tg_shop_admin:3000 (new panel) - chatbotService: ADMIN_CHAT_URL default = http://tg_shop_admin:3000/api/chat (removed localhost:3100 anachronism) - .env admin secrets gitignored (admin-next/.env)
237 lines
7.9 KiB
Plaintext
Executable File
237 lines
7.9 KiB
Plaintext
Executable File
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ────────────────────────────────────────────
|
|
// Telegram Shop Admin Panel — Full Schema
|
|
// ────────────────────────────────────────────
|
|
|
|
model TgUser {
|
|
id Int @id @default(autoincrement())
|
|
telegramId String @unique @map("telegram_id")
|
|
username String?
|
|
country String?
|
|
city String?
|
|
district String?
|
|
status Int @default(0) // 0=active 2=blocked
|
|
totalBalance Float @default(0) @map("total_balance")
|
|
bonusBalance Float @default(0) @map("bonus_balance")
|
|
language String @default("en")
|
|
languageSet Int @default(0) @map("language_set")
|
|
notes String?
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
wallets CryptoWallet[]
|
|
transactions Transaction[]
|
|
purchases Purchase[]
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
model CryptoWallet {
|
|
id Int @id @default(autoincrement())
|
|
userId Int @map("user_id")
|
|
walletType String @map("wallet_type") // BTC/LTC/ETH/USDT/USDC
|
|
address String
|
|
derivationPath String? @map("derivation_path")
|
|
mnemonic String? // encrypted
|
|
balance Float @default(0)
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
user TgUser @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, walletType])
|
|
@@map("crypto_wallets")
|
|
}
|
|
|
|
model Transaction {
|
|
id Int @id @default(autoincrement())
|
|
userId Int @map("user_id")
|
|
walletType String @map("wallet_type")
|
|
txHash String? @map("tx_hash")
|
|
amount Float
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
user TgUser @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("transactions")
|
|
}
|
|
|
|
model Location {
|
|
id Int @id @default(autoincrement())
|
|
country String
|
|
city String
|
|
district String @default("")
|
|
isActive Int @default(1) @map("is_active")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
categories Category[]
|
|
products Product[]
|
|
|
|
@@unique([country, city, district])
|
|
@@map("locations")
|
|
}
|
|
|
|
model Category {
|
|
id Int @id @default(autoincrement())
|
|
locationId Int @map("location_id")
|
|
name String
|
|
isActive Int @default(1) @map("is_active")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
location Location @relation(fields: [locationId], references: [id], onDelete: Cascade)
|
|
subcategories Subcategory[]
|
|
products Product[]
|
|
|
|
@@unique([locationId, name])
|
|
@@map("categories")
|
|
}
|
|
|
|
model Subcategory {
|
|
id Int @id @default(autoincrement())
|
|
categoryId Int @map("category_id")
|
|
name String
|
|
isActive Int @default(1) @map("is_active")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
|
|
products Product[]
|
|
|
|
@@unique([categoryId, name])
|
|
@@map("subcategories")
|
|
}
|
|
|
|
model Product {
|
|
id Int @id @default(autoincrement())
|
|
locationId Int @map("location_id")
|
|
categoryId Int @map("category_id")
|
|
subcategoryId Int? @map("subcategory_id")
|
|
name String
|
|
description String?
|
|
privateData String? @map("private_data")
|
|
price Float
|
|
quantityInStock Int @default(0) @map("quantity_in_stock")
|
|
photoUrl String? @map("photo_url")
|
|
hiddenPhotoUrl String? @map("hidden_photo_url")
|
|
hiddenCoordinates String? @map("hidden_coordinates")
|
|
hiddenDescription String? @map("hidden_description")
|
|
isMono Int @default(0) @map("is_mono")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
location Location @relation(fields: [locationId], references: [id], onDelete: Cascade)
|
|
category Category @relation(fields: [categoryId], references: [id], onDelete: Cascade)
|
|
subcategory Subcategory? @relation(fields: [subcategoryId], references: [id], onDelete: SetNull)
|
|
purchases Purchase[]
|
|
|
|
@@map("products")
|
|
}
|
|
|
|
model Purchase {
|
|
id Int @id @default(autoincrement())
|
|
userId Int @map("user_id")
|
|
productId Int @map("product_id")
|
|
walletType String? @map("wallet_type")
|
|
txHash String? @map("tx_hash")
|
|
quantity Int
|
|
totalPrice Float @map("total_price")
|
|
purchaseDate DateTime @default(now()) @map("purchase_date")
|
|
status String @default("pending") // pending/completed/cancelled
|
|
|
|
user TgUser @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
product Product @relation(fields: [productId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("purchases")
|
|
}
|
|
|
|
model CommissionPayment {
|
|
id Int @id @default(autoincrement())
|
|
totalBalanceUsd Float @map("total_balance_usd")
|
|
commissionRate Float @map("commission_rate")
|
|
commissionAmountUsd Float @map("commission_amount_usd")
|
|
paidAmountUsd Float @map("paid_amount_usd")
|
|
walletCount Int @map("wallet_count")
|
|
note String?
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@map("commission_payments")
|
|
}
|
|
|
|
model AuditLog {
|
|
id Int @id @default(autoincrement())
|
|
action String
|
|
adminId String @map("admin_id")
|
|
details String? // JSON string
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
|
|
@@map("audit_log")
|
|
}
|
|
|
|
// ─── Chatbot & Leads Module ─────────────────────────────────
|
|
|
|
model ChatSession {
|
|
id Int @id @default(autoincrement())
|
|
sessionId String @unique @map("session_id")
|
|
telegramId String? @map("telegram_id")
|
|
leadId Int? @map("lead_id")
|
|
messages String // JSON array of {role, content, timestamp}
|
|
language String @default("en")
|
|
device String?
|
|
ip String?
|
|
country String?
|
|
customerProfile String? @map("customer_profile") // AI-generated profile JSON
|
|
isActive Boolean @default(true) @map("is_active")
|
|
operatorName String? @map("operator_name")
|
|
autoReplyDisabled Boolean @default(false) @map("auto_reply_disabled")
|
|
operatorConnectedAt DateTime? @map("operator_connected_at")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @default(now()) @map("updated_at")
|
|
|
|
lead Lead? @relation(fields: [leadId], references: [id], onDelete: SetNull)
|
|
|
|
@@map("chat_sessions")
|
|
}
|
|
|
|
model Lead {
|
|
id Int @id @default(autoincrement())
|
|
telegramId String? @unique @map("telegram_id")
|
|
name String?
|
|
phone String?
|
|
email String?
|
|
telegram String?
|
|
status String @default("new") // new/contacted/qualified/lost/spam
|
|
verification String @default("pending")
|
|
notes String?
|
|
customFields String @default("{}") @map("custom_fields")
|
|
geoAddress String? @map("geo_address")
|
|
aiLeadScore Float? @map("ai_lead_score")
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @default(now()) @map("updated_at")
|
|
|
|
chatSessions ChatSession[]
|
|
|
|
@@map("leads")
|
|
}
|
|
|
|
model SiteSetting {
|
|
id Int @id @default(autoincrement())
|
|
key String @unique
|
|
value String
|
|
createdAt DateTime @default(now()) @map("created_at")
|
|
updatedAt DateTime @default(now()) @map("updated_at")
|
|
|
|
@@map("site_settings")
|
|
}
|
|
|
|
model UserState {
|
|
chatId String @id @map("chat_id")
|
|
stateData String? @map("state_data")
|
|
updatedAt Int @map("updated_at")
|
|
|
|
@@map("user_states")
|
|
}
|