Files
mp-pilates/packages/server/prisma/schema.prisma

415 lines
14 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
// ===== Enums =====
enum UserRole {
MEMBER
ADMIN
}
enum CardTypeCategory {
TIMES
DURATION
TRIAL
}
enum MembershipStatus {
ACTIVE
EXPIRED
USED_UP
}
enum TimeSlotStatus {
OPEN
FULL
CLOSED
}
enum TimeSlotSource {
TEMPLATE
MANUAL
}
enum BookingStatus {
PENDING_CONFIRMATION
CONFIRMED
CANCELLED
COMPLETED
NO_SHOW
}
enum OrderStatus {
PENDING
PAID
REFUNDED
}
enum InviteReferralStatus {
REGISTERED
TRIAL_PURCHASED
QUALIFIED
}
// ===== Models =====
model User {
id String @id @default(uuid())
inviteCode String? @unique @map("invite_code") @db.VarChar(6)
openid String @unique
unionid String?
phone String?
nickname String @default("")
avatarUrl String? @map("avatar_url")
role UserRole @default(MEMBER)
adminBookingSubscriptionCount Int @default(0) @map("admin_booking_subscription_count")
lastLoginAt DateTime? @map("last_login_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
bodyMetrics BodyMetric[]
memberNotes MemberNote[]
progressPhotos ProgressPhoto[]
lessonSupplements LessonSupplement[]
memberships Membership[]
bookings Booking[]
orders Order[]
subscriptionMessageConsents SubscriptionMessageConsent[]
sentInviteReferrals InviteReferral[] @relation("InviteReferralInviter")
receivedInviteReferral InviteReferral[] @relation("InviteReferralInvitee")
inviteRewardGrants InviteRewardGrant[] @relation("InviteRewardGrantInviter")
@@map("users")
}
model SubscriptionMessageConsent {
id String @id @default(uuid())
userId String @map("user_id")
templateId String @map("template_id")
scene String
totalRequestCount Int @default(0) @map("total_request_count")
acceptCount Int @default(0) @map("accept_count")
rejectCount Int @default(0) @map("reject_count")
banCount Int @default(0) @map("ban_count")
filterCount Int @default(0) @map("filter_count")
sentCount Int @default(0) @map("sent_count")
lastResult String @map("last_result")
lastRequestedAt DateTime @default(now()) @map("last_requested_at")
lastSentAt DateTime? @map("last_sent_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id])
@@unique([userId, templateId, scene])
@@index([userId])
@@index([scene])
@@map("subscription_message_consents")
}
model CardType {
id String @id @default(uuid())
name String
type CardTypeCategory
totalTimes Int? @map("total_times")
durationDays Int @map("duration_days")
price Decimal @db.Decimal(10, 0)
originalPrice Decimal? @map("original_price") @db.Decimal(10, 0)
description String?
coverUrl String? @map("cover_url")
isActive Boolean @default(true) @map("is_active")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
memberships Membership[]
orders Order[]
@@map("card_types")
}
model Membership {
id String @id @default(uuid())
userId String @map("user_id")
cardTypeId String @map("card_type_id")
remainingTimes Int? @map("remaining_times")
totalTimes Int? @map("total_times")
startDate DateTime @map("start_date")
expireDate DateTime @map("expire_date")
status MembershipStatus @default(ACTIVE)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
lessonSupplements LessonSupplement[]
user User @relation(fields: [userId], references: [id])
cardType CardType @relation(fields: [cardTypeId], references: [id])
bookings Booking[]
orders Order[]
inviteRewardGrants InviteRewardGrant[]
@@index([userId])
@@index([userId, cardTypeId])
@@index([status])
@@map("memberships")
}
model WeekTemplate {
id String @id @default(uuid())
dayOfWeek Int @map("day_of_week")
startTime String @map("start_time")
endTime String @map("end_time")
capacity Int @default(1)
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
timeSlots TimeSlot[]
@@map("week_templates")
}
model TimeSlot {
id String @id @default(uuid())
date DateTime @db.Date
startTime String @map("start_time")
endTime String @map("end_time")
capacity Int @default(1)
bookedCount Int @default(0) @map("booked_count")
status TimeSlotStatus @default(OPEN)
source TimeSlotSource @default(TEMPLATE)
templateId String? @map("template_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
template WeekTemplate? @relation(fields: [templateId], references: [id])
bookings Booking[]
@@unique([date, startTime, endTime])
@@index([date])
@@index([status])
@@map("time_slots")
}
model Booking {
id String @id @default(uuid())
userId String @map("user_id")
timeSlotId String @map("time_slot_id")
membershipId String @map("membership_id")
membershipTimesDeducted Boolean? @map("membership_times_deducted")
status BookingStatus @default(PENDING_CONFIRMATION)
cancelledAt DateTime? @map("cancelled_at")
confirmedAt DateTime? @map("confirmed_at")
completedAt DateTime? @map("completed_at")
operatorId String? @map("operator_id")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id])
timeSlot TimeSlot @relation(fields: [timeSlotId], references: [id])
membership Membership @relation(fields: [membershipId], references: [id])
qualifiedInviteReferrals InviteReferral[]
review BookingReview?
memberNotes MemberNote[]
reviewReminderDueAt DateTime? @map("review_reminder_due_at")
reviewReminderClaimedAt DateTime? @map("review_reminder_claimed_at")
reviewReminderSentAt DateTime? @map("review_reminder_sent_at")
classReminderDueAt DateTime? @map("class_reminder_due_at")
classReminderClaimedAt DateTime? @map("class_reminder_claimed_at")
classReminderSentAt DateTime? @map("class_reminder_sent_at")
statusHistory BookingStatusHistory[]
@@unique([userId, timeSlotId])
@@index([userId])
@@index([status])
@@map("bookings")
}
model BookingStatusHistory {
id String @id @default(uuid())
bookingId String @map("booking_id")
fromStatus String? @map("from_status")
toStatus String @map("to_status")
operatorId String? @map("operator_id")
remark String?
createdAt DateTime @default(now()) @map("created_at")
booking Booking @relation(fields: [bookingId], references: [id])
@@index([bookingId])
@@map("booking_status_history")
}
model Order {
id String @id @default(uuid())
userId String @map("user_id")
cardTypeId String @map("card_type_id")
membershipId String? @map("membership_id")
orderNo String @unique @map("order_no")
inviteInviterId String? @map("invite_inviter_id")
purchasedCategory String? @map("purchased_category")
amount Decimal @db.Decimal(10, 0)
status OrderStatus @default(PENDING)
wxTransactionId String? @map("wx_transaction_id")
paidAt DateTime? @map("paid_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
user User @relation(fields: [userId], references: [id])
cardType CardType @relation(fields: [cardTypeId], references: [id])
membership Membership? @relation(fields: [membershipId], references: [id])
inviteReferrals InviteReferral[]
@@index([userId])
@@index([status])
@@index([membershipId])
@@map("orders")
}
model InviteReferral {
id String @id @default(uuid())
inviterId String @map("inviter_id")
inviteeId String @unique @map("invitee_id")
status InviteReferralStatus @default(REGISTERED)
trialOrderId String? @unique @map("trial_order_id")
qualifiedBookingId String? @unique @map("qualified_booking_id")
invitedAt DateTime @default(now()) @map("invited_at")
trialPurchasedAt DateTime? @map("trial_purchased_at")
qualifiedAt DateTime? @map("qualified_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
inviter User @relation("InviteReferralInviter", fields: [inviterId], references: [id])
invitee User @relation("InviteReferralInvitee", fields: [inviteeId], references: [id])
trialOrder Order? @relation(fields: [trialOrderId], references: [id])
qualifiedBooking Booking? @relation(fields: [qualifiedBookingId], references: [id])
@@unique([inviterId, inviteeId])
@@index([inviterId, status])
@@index([status])
@@map("invite_referrals")
}
model InviteRewardGrant {
id String @id @default(uuid())
inviterId String @map("inviter_id")
membershipId String? @map("membership_id")
qualifiedReferralCount Int @map("qualified_referral_count")
rewardTimes Int @default(1) @map("reward_times")
grantedAt DateTime @default(now()) @map("granted_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
inviter User @relation("InviteRewardGrantInviter", fields: [inviterId], references: [id])
membership Membership? @relation(fields: [membershipId], references: [id], onDelete: Restrict)
@@index([inviterId, grantedAt])
@@map("invite_reward_grants")
}
model StudioConfig {
id String @id @default(uuid())
name String
logo String?
bannerUrl String? @map("banner_url")
address String @default("")
phone String @default("")
latitude Decimal? @db.Decimal(10, 7)
longitude Decimal? @db.Decimal(10, 7)
cancelHoursLimit Int @default(2) @map("cancel_hours_limit")
photos Json @default("[]")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("studio_config")
}
// Historical totals without fabricated scheduled dates.
model LessonSupplement {
id String @id @default(uuid())
userId String @map("user_id")
requestId String @map("request_id") @db.VarChar(80)
quantity Int
membershipId String? @map("membership_id")
deductedTimes Int @default(0) @map("deducted_times")
cardName String? @map("card_name")
remark String? @db.VarChar(200)
operatorId String @map("operator_id")
operatorName String @map("operator_name")
createdAt DateTime @default(now()) @map("created_at")
revokedAt DateTime? @map("revoked_at")
revokedBy String? @map("revoked_by")
user User @relation(fields: [userId], references: [id])
membership Membership? @relation(fields: [membershipId], references: [id], onDelete: Restrict)
@@unique([userId, requestId])
@@index([userId, revokedAt, createdAt])
@@map("lesson_supplements")
}
model BookingReview {
id String @id @default(uuid())
bookingId String @unique @map("booking_id")
rating Int
recommendation Int?
tags Json
comment String @db.VarChar(200)
createdAt DateTime @default(now()) @map("created_at")
booking Booking @relation(fields: [bookingId], references: [id])
@@index([createdAt])
@@map("booking_reviews")
}
model BodyMetric {
id String @id @default(uuid())
userId String @map("user_id")
recordedAt DateTime @db.Date @map("recorded_at")
weight Float?
bodyFat Float? @map("body_fat")
waist Float?
hip Float?
flexibility Float?
remark String @default("") @db.VarChar(200)
operatorId String @map("operator_id")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id])
@@index([userId, recordedAt])
@@map("body_metrics")
}
model MemberNote {
id String @id @default(uuid())
userId String @map("user_id")
bookingId String? @map("booking_id")
content String @db.VarChar(1000)
shared Boolean @default(false)
operatorId String @map("operator_id")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id])
booking Booking? @relation(fields: [bookingId], references: [id])
@@index([userId, createdAt])
@@map("member_notes")
}
model ProgressPhoto {
id String @id @default(uuid())
userId String @map("user_id")
objectKey String @unique @map("object_key")
caption String @default("") @db.VarChar(200)
recordedAt DateTime @db.Date @map("recorded_at")
uploadedAt DateTime? @map("uploaded_at")
consentedAt DateTime? @map("consented_at")
revokedAt DateTime? @map("revoked_at")
operatorId String @map("operator_id")
createdAt DateTime @default(now()) @map("created_at")
user User @relation(fields: [userId], references: [id])
@@index([userId, recordedAt])
@@map("progress_photos")
}