- NestJS + TypeScript + Prisma + PostgreSQL 工程骨架 - 微信登录安全流程:服务端 code2Session 换 openid 后签发 JWT, session_key 缓存于 Redis,不信任前端 openid - 统一响应/异常处理、JWT 全局鉴权(@Public 豁免)、Swagger 文档 - Prisma 全量核心 schema(用户/分类/商品/设计清单/地址/订单/支付/上传/定制任务)+ seed - 业务模块空壳(商品/分类/设计清单/地址/订单/支付/上传/BullMQ 队列) - Docker 多阶段镜像 + 本地/生产 docker-compose - docs:密钥获取指南、COS SDK 移除记录 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
221 lines
5.9 KiB
Plaintext
221 lines
5.9 KiB
Plaintext
// 微信小程序后端 — Prisma schema
|
|
// 数据库:PostgreSQL
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ── 用户 ──────────────────────────────────────────────
|
|
model User {
|
|
id String @id @default(cuid())
|
|
openid String @unique
|
|
unionid String?
|
|
nickname String?
|
|
avatar String?
|
|
phone String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
orders Order[]
|
|
addresses Address[]
|
|
designLists DesignList[]
|
|
uploads Upload[]
|
|
customizations CustomizationTask[]
|
|
|
|
@@index([phone])
|
|
}
|
|
|
|
// ── 商品分类 ──────────────────────────────────────────
|
|
model Category {
|
|
id String @id @default(cuid())
|
|
name String
|
|
parentId String?
|
|
sort Int @default(0)
|
|
parent Category? @relation("CategoryTree", fields: [parentId], references: [id])
|
|
children Category[] @relation("CategoryTree")
|
|
products Product[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([parentId])
|
|
}
|
|
|
|
// ── 商品 ──────────────────────────────────────────────
|
|
model Product {
|
|
id String @id @default(cuid())
|
|
name String
|
|
categoryId String?
|
|
price Decimal @db.Decimal(10, 2)
|
|
images String[]
|
|
description String?
|
|
status ProductStatus @default(DRAFT)
|
|
category Category? @relation(fields: [categoryId], references: [id])
|
|
orderItems OrderItem[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([categoryId])
|
|
@@index([status])
|
|
}
|
|
|
|
enum ProductStatus {
|
|
DRAFT
|
|
ON_SALE
|
|
OFF_SHELF
|
|
}
|
|
|
|
// ── 设计清单 / 定制需求 ───────────────────────────────
|
|
model DesignList {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
title String
|
|
items Json
|
|
status DesignListStatus @default(DRAFT)
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
customizations CustomizationTask[]
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId])
|
|
}
|
|
|
|
enum DesignListStatus {
|
|
DRAFT
|
|
SUBMITTED
|
|
PROCESSING
|
|
DONE
|
|
}
|
|
|
|
// ── 收货地址 ──────────────────────────────────────────
|
|
model Address {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
name String
|
|
phone String
|
|
province String
|
|
city String
|
|
district String
|
|
detail String
|
|
isDefault Boolean @default(false)
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId])
|
|
}
|
|
|
|
// ── 订单 ──────────────────────────────────────────────
|
|
model Order {
|
|
id String @id @default(cuid())
|
|
orderNo String @unique
|
|
userId String
|
|
status OrderStatus @default(PENDING)
|
|
totalAmount Decimal @db.Decimal(10, 2)
|
|
addressSnapshot Json
|
|
user User @relation(fields: [userId], references: [id])
|
|
items OrderItem[]
|
|
payment Payment?
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([userId])
|
|
@@index([status])
|
|
}
|
|
|
|
enum OrderStatus {
|
|
PENDING
|
|
PAID
|
|
PROCESSING
|
|
SHIPPED
|
|
COMPLETED
|
|
CANCELLED
|
|
}
|
|
|
|
model OrderItem {
|
|
id String @id @default(cuid())
|
|
orderId String
|
|
productId String?
|
|
name String
|
|
price Decimal @db.Decimal(10, 2)
|
|
quantity Int
|
|
order Order @relation(fields: [orderId], references: [id], onDelete: Cascade)
|
|
product Product? @relation(fields: [productId], references: [id])
|
|
|
|
@@index([orderId])
|
|
}
|
|
|
|
// ── 支付 ──────────────────────────────────────────────
|
|
model Payment {
|
|
id String @id @default(cuid())
|
|
orderId String @unique
|
|
transactionId String?
|
|
provider PaymentProvider @default(WECHAT)
|
|
status PaymentStatus @default(PENDING)
|
|
paidAt DateTime?
|
|
order Order @relation(fields: [orderId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|
|
|
|
enum PaymentProvider {
|
|
WECHAT
|
|
}
|
|
|
|
enum PaymentStatus {
|
|
PENDING
|
|
SUCCESS
|
|
REFUNDED
|
|
}
|
|
|
|
// ── 文件上传 ──────────────────────────────────────────
|
|
model Upload {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
cosKey String
|
|
url String
|
|
mimetype String?
|
|
size Int?
|
|
user User @relation(fields: [userId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
@@index([userId])
|
|
}
|
|
|
|
// ── 异步定制任务 ──────────────────────────────────────
|
|
model CustomizationTask {
|
|
id String @id @default(cuid())
|
|
designListId String?
|
|
userId String?
|
|
status CustomizationTaskStatus @default(PENDING)
|
|
resultUrl String?
|
|
queueJobId String?
|
|
designList DesignList? @relation(fields: [designListId], references: [id])
|
|
user User? @relation(fields: [userId], references: [id])
|
|
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([designListId])
|
|
@@index([status])
|
|
}
|
|
|
|
enum CustomizationTaskStatus {
|
|
PENDING
|
|
RUNNING
|
|
SUCCESS
|
|
FAILED
|
|
}
|