Files
wxmp_backend/prisma/schema.prisma
T
lhmin0604andClaude 05584172ca feat(orders): 对齐契约 §6——服务端重算金额/地址快照/requestId 幂等/分页 + confirm/cancel 接口
- POST /api/orders 改为 { addressId, items[{productId,quantity}], designListId?, requestId? },
  totalAmount 按 Product 真实价格重算,客户端不再可传金额(DTO 白名单同步收紧)
- requestId 幂等:Order 新增唯一列 + 迁移 20260915000000,重复请求返回已创建订单
- GET /api/orders 支持 status/page/pageSize,返回 { list, total, page, pageSize }
- GET /api/orders/:id 补本人校验(越权 403 / 不存在 404)
- 新增 PATCH /api/orders/:id/confirm(SHIPPED→COMPLETED)、POST /api/orders/:id/cancel(仅 PENDING)
- 下单事务内推进设计清单 DRAFT/SUBMITTED→PROCESSING(单向,R2 交接的状态触发权)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-09-15 06:06:38 +08:00

261 lines
7.3 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 微信小程序后端 — 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:登录判定主键。首次登录验证手机号注册,后续登录 openid 在库即放行
openid String @unique
// 插件用户标识(当前未用插件,保留可空以兼容未来)
openpid 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[]
wordCloudJobs WordCloudJob[]
@@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[]
orders Order[]
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
// 关联的设计清单(R4 下单后 WCD 派单据此读取 designData
designListId String?
// 客户端幂等键(api-contract-v1 §6requestId 重复请求返回已创建订单)
requestId String? @unique
user User @relation(fields: [userId], references: [id])
designList DesignList? @relation(fields: [designListId], references: [id])
items OrderItem[]
payment Payment?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([userId])
@@index([status])
@@index([designListId])
}
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?
// R4 下单后 WCD 派单:关联的订单与词云任务
orderId String?
wordcloudJobId 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([orderId])
@@index([status])
}
enum CustomizationTaskStatus {
PENDING
RUNNING
SUCCESS
FAILED
}
// ── 词云任务(R4:小程序交互生成 + 下单 WCD 派单共用)────────────────
model WordCloudJob {
id String @id @default(cuid())
userId String
// wordcloud 侧的外部 job_idPOST /api/jobs 返回);空表示尚未在外部创建
remoteJobId String?
status WordCloudJobStatus @default(QUEUED)
progress Int @default(0)
imageUrl String?
error String?
user User @relation(fields: [userId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([userId])
}
enum WordCloudJobStatus {
QUEUED
RUNNING
SUCCESS
FAILED
}