Files
wxmp_backend/prisma/schema.prisma
T
broccoliandClaude Fable 5 1d946046d2 feat: 微信登录与认证完善 + 一键 docker compose 启动
登录流程(以 openid 为唯一标识):
- auth.service.login 改为 upsert:openid 在库续登,不在库自动建用户签 token
- 个人主体无 getPhoneNumber 权限,故不强制手机号注册;register 接口保留备未来用
- wechat.service 新增 getAccessToken(Redis 缓存)、getPluginOpenPid、getUserPhoneNumber
- 新增 /api/wechat/plugin-openpid、/api/wechat/phone 接口

schema 与迁移:
- User 增加 openpid(可空唯一) 兼容插件场景;openid 保持必填主键
- 新增 add_openpid_optional_openid、openid_required_primary 迁移

部署:
- docker-compose.yml 改为 docker compose up -d 一键启动 postgres+redis+app
- app 容器内用服务名连 db/redis,启动自动跑 prisma migrate deploy
- 端口统一 3090(Dockerfile EXPOSE、compose 映射同步)
- 新增 docs/wechat-api-signature-guide.md API 签名手册

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-05 21:21:09 +08:00

224 lines
6.1 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:登录判定主键。首次登录验证手机号注册,后续登录 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[]
@@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
}