feat: ESP32 DIY platform Phase 1 — marketplace with mock payment & flash token flow
- React+Vite frontend (dark theme, role-based routing: admin/seller/buyer) - Express+Prisma+PostgreSQL backend with JWT auth and audit logging - MinIO object storage with backend proxy for CORS-free firmware delivery - Mock payment flow (order → mock-pay → FlashToken) for pre-business testing - FlashToken lifecycle: issue → validate → esp-web-tools manifest → consume - Admin approval workflow for project/product submissions - Toss Payments integration guide (TOSS_PAYMENT_GUIDE.md) for live keys Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
204
backend/prisma/schema.prisma
Normal file
204
backend/prisma/schema.prisma
Normal file
@@ -0,0 +1,204 @@
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
datasource db {
|
||||
provider = "postgresql"
|
||||
url = env("DATABASE_URL")
|
||||
}
|
||||
|
||||
enum UserRole {
|
||||
admin
|
||||
seller
|
||||
buyer
|
||||
}
|
||||
|
||||
enum ProjectStatus {
|
||||
draft
|
||||
pending
|
||||
approved
|
||||
rejected
|
||||
suspended
|
||||
}
|
||||
|
||||
enum OrderStatus {
|
||||
pending
|
||||
paid
|
||||
cancelled
|
||||
refunded
|
||||
}
|
||||
|
||||
enum PaymentGateway {
|
||||
toss
|
||||
stripe
|
||||
}
|
||||
|
||||
model User {
|
||||
id String @id @default(uuid())
|
||||
email String @unique
|
||||
passwordHash String
|
||||
nickname String @unique
|
||||
role UserRole @default(buyer)
|
||||
profileImageUrl String?
|
||||
isEmailVerified Boolean @default(false)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
lastLoginAt DateTime?
|
||||
lastLoginIp String?
|
||||
|
||||
projects Project[]
|
||||
orders Order[]
|
||||
reviews Review[]
|
||||
auditLogs AuditLog[]
|
||||
}
|
||||
|
||||
model Project {
|
||||
id String @id @default(uuid())
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
title String
|
||||
description String @db.Text
|
||||
difficultyLevel Int @default(3)
|
||||
chipFamily String @default("ESP32-S3")
|
||||
requiredParts Json?
|
||||
status ProjectStatus @default(draft)
|
||||
adminNote String?
|
||||
commissionRate Float @default(0.1)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
files ProjectFile[]
|
||||
product Product?
|
||||
}
|
||||
|
||||
model ProjectFile {
|
||||
id String @id @default(uuid())
|
||||
projectId String
|
||||
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
|
||||
fileType String
|
||||
url String
|
||||
thumbnailUrl String?
|
||||
fileSize Int
|
||||
mimeType String
|
||||
originalName String?
|
||||
flashOffset String @default("0x0")
|
||||
displayOrder Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model Product {
|
||||
id String @id @default(uuid())
|
||||
projectId String @unique
|
||||
project Project @relation(fields: [projectId], references: [id])
|
||||
price Int
|
||||
isOnSale Boolean @default(true)
|
||||
totalSales Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
orders Order[]
|
||||
reviews Review[]
|
||||
}
|
||||
|
||||
model Order {
|
||||
id String @id @default(uuid())
|
||||
buyerId String
|
||||
buyer User @relation(fields: [buyerId], references: [id])
|
||||
productId String
|
||||
product Product @relation(fields: [productId], references: [id])
|
||||
amount Int
|
||||
commissionAmount Int
|
||||
sellerAmount Int
|
||||
paymentGateway PaymentGateway @default(toss)
|
||||
paymentKey String?
|
||||
tossOrderId String? @unique
|
||||
status OrderStatus @default(pending)
|
||||
buyerInfo Json
|
||||
deviceInfo Json?
|
||||
orderedAt DateTime @default(now())
|
||||
paidAt DateTime?
|
||||
refundedAt DateTime?
|
||||
refundReason String?
|
||||
|
||||
flashToken FlashToken?
|
||||
review Review?
|
||||
}
|
||||
|
||||
model FlashToken {
|
||||
id String @id @default(uuid())
|
||||
token String @unique @default(uuid())
|
||||
orderId String @unique
|
||||
order Order @relation(fields: [orderId], references: [id])
|
||||
isUsed Boolean @default(false)
|
||||
usedAt DateTime?
|
||||
macAddress String?
|
||||
chipFamily String?
|
||||
expiresAt DateTime
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
flashLog FlashLog?
|
||||
}
|
||||
|
||||
model FlashLog {
|
||||
id String @id @default(uuid())
|
||||
flashTokenId String @unique
|
||||
flashToken FlashToken @relation(fields: [flashTokenId], references: [id])
|
||||
macAddress String
|
||||
chipFamily String
|
||||
firmwareName String
|
||||
firmwareId String
|
||||
success Boolean
|
||||
errorMessage String?
|
||||
clientIp String
|
||||
userAgent String?
|
||||
flashedAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model Review {
|
||||
id String @id @default(uuid())
|
||||
orderId String @unique
|
||||
order Order @relation(fields: [orderId], references: [id])
|
||||
userId String
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
productId String
|
||||
product Product @relation(fields: [productId], references: [id])
|
||||
rating Int
|
||||
title String
|
||||
content String @db.Text
|
||||
isVisible Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
media ReviewMedia[]
|
||||
}
|
||||
|
||||
model ReviewMedia {
|
||||
id String @id @default(uuid())
|
||||
reviewId String
|
||||
review Review @relation(fields: [reviewId], references: [id], onDelete: Cascade)
|
||||
mediaType String
|
||||
url String
|
||||
thumbnailUrl String?
|
||||
createdAt DateTime @default(now())
|
||||
}
|
||||
|
||||
model AuditLog {
|
||||
id String @id @default(uuid())
|
||||
userId String?
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
action String
|
||||
targetType String?
|
||||
targetId String?
|
||||
ipAddress String
|
||||
userAgent String?
|
||||
requestMethod String?
|
||||
requestPath String?
|
||||
requestBody Json?
|
||||
responseStatus Int?
|
||||
metadata Json?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@index([userId])
|
||||
@@index([action])
|
||||
@@index([createdAt])
|
||||
}
|
||||
Reference in New Issue
Block a user