feat: 新增个人身体画像评估与馆主经营助手
把 3 分钟身体状态评估做成独立获客链路,匿名测评后登录认领完整报告,并接入体验预约与今日待办。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -84,6 +84,15 @@ model User {
|
||||
sentInviteReferrals InviteReferral[] @relation("InviteReferralInviter")
|
||||
receivedInviteReferral InviteReferral[] @relation("InviteReferralInvitee")
|
||||
inviteRewardGrants InviteRewardGrant[] @relation("InviteRewardGrantInviter")
|
||||
bodyPortraitVisits BodyPortraitVisit[] @relation("PortraitVisitUser")
|
||||
referredPortraitVisits BodyPortraitVisit[] @relation("PortraitReferrer")
|
||||
bodyPortraitAssessments BodyPortraitAssessment[]
|
||||
growthLead GrowthLead?
|
||||
growthEvents GrowthEvent[]
|
||||
professionalAssessments ProfessionalAssessmentSession[]
|
||||
trainingPlans TrainingPlan[]
|
||||
reassessmentTodos ReassessmentTodo[]
|
||||
growthShareCards GrowthShareCard[]
|
||||
|
||||
@@map("users")
|
||||
}
|
||||
@@ -207,13 +216,16 @@ model Booking {
|
||||
confirmedAt DateTime? @map("confirmed_at")
|
||||
completedAt DateTime? @map("completed_at")
|
||||
operatorId String? @map("operator_id")
|
||||
originAssessmentId String? @map("origin_assessment_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])
|
||||
originAssessment BodyPortraitAssessment? @relation(fields: [originAssessmentId], references: [id])
|
||||
qualifiedInviteReferrals InviteReferral[]
|
||||
professionalAssessments ProfessionalAssessmentSession[]
|
||||
|
||||
review BookingReview?
|
||||
memberNotes MemberNote[]
|
||||
@@ -228,6 +240,7 @@ model Booking {
|
||||
@@unique([userId, timeSlotId])
|
||||
@@index([userId])
|
||||
@@index([status])
|
||||
@@index([originAssessmentId])
|
||||
@@map("bookings")
|
||||
}
|
||||
|
||||
@@ -407,8 +420,203 @@ model ProgressPhoto {
|
||||
consentedAt DateTime? @map("consented_at")
|
||||
revokedAt DateTime? @map("revoked_at")
|
||||
operatorId String @map("operator_id")
|
||||
angle String? @db.VarChar(16)
|
||||
sessionId String? @map("session_id")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
session ProfessionalAssessmentSession? @relation(fields: [sessionId], references: [id])
|
||||
@@index([userId, recordedAt])
|
||||
@@index([sessionId])
|
||||
@@map("progress_photos")
|
||||
}
|
||||
|
||||
model BodyPortraitVisit {
|
||||
id String @id @default(uuid())
|
||||
tokenHash String @unique @map("token_hash") @db.VarChar(64)
|
||||
source String @default("organic") @db.VarChar(32)
|
||||
campaignId String? @map("campaign_id") @db.VarChar(40)
|
||||
referralCode String? @map("referral_code") @db.VarChar(12)
|
||||
referrerUserId String? @map("referrer_user_id")
|
||||
landingPath String @default("") @map("landing_path") @db.VarChar(120)
|
||||
userId String? @map("user_id")
|
||||
firstSeenAt DateTime @default(now()) @map("first_seen_at")
|
||||
lastSeenAt DateTime @default(now()) @map("last_seen_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
user User? @relation("PortraitVisitUser", fields: [userId], references: [id])
|
||||
referrer User? @relation("PortraitReferrer", fields: [referrerUserId], references: [id])
|
||||
assessments BodyPortraitAssessment[]
|
||||
events GrowthEvent[]
|
||||
|
||||
@@index([source, createdAt])
|
||||
@@index([userId])
|
||||
@@map("body_portrait_visits")
|
||||
}
|
||||
|
||||
model BodyPortraitAssessment {
|
||||
id String @id @default(uuid())
|
||||
visitId String @map("visit_id")
|
||||
userId String? @map("user_id")
|
||||
tokenHash String @unique @map("token_hash") @db.VarChar(64)
|
||||
questionnaireVersion String @map("questionnaire_version") @db.VarChar(32)
|
||||
rulesVersion String @map("rules_version") @db.VarChar(32)
|
||||
status String @default("DRAFT") @db.VarChar(16)
|
||||
answers Json @default("{}")
|
||||
safetyFlagged Boolean @default(false) @map("safety_flagged")
|
||||
report Json?
|
||||
completedAt DateTime? @map("completed_at")
|
||||
claimedAt DateTime? @map("claimed_at")
|
||||
expiresAt DateTime @map("expires_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
visit BodyPortraitVisit @relation(fields: [visitId], references: [id])
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
bookings Booking[]
|
||||
growthLeads GrowthLead[]
|
||||
events GrowthEvent[]
|
||||
professionalAssessments ProfessionalAssessmentSession[]
|
||||
|
||||
@@index([visitId])
|
||||
@@index([userId, createdAt])
|
||||
@@index([status, expiresAt])
|
||||
@@map("body_portrait_assessments")
|
||||
}
|
||||
|
||||
model GrowthLead {
|
||||
id String @id @default(uuid())
|
||||
userId String @unique @map("user_id")
|
||||
latestAssessmentId String? @map("latest_assessment_id")
|
||||
stage String @default("CLAIMED") @db.VarChar(32)
|
||||
source String? @db.VarChar(32)
|
||||
campaignId String? @map("campaign_id") @db.VarChar(40)
|
||||
lastActiveAt DateTime @default(now()) @map("last_active_at")
|
||||
coachNote String @default("") @map("coach_note") @db.VarChar(500)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
latestAssessment BodyPortraitAssessment? @relation(fields: [latestAssessmentId], references: [id])
|
||||
|
||||
@@index([stage, lastActiveAt])
|
||||
@@map("growth_leads")
|
||||
}
|
||||
|
||||
model GrowthEvent {
|
||||
id String @id @default(uuid())
|
||||
name String @db.VarChar(40)
|
||||
idempotencyKey String @unique @map("idempotency_key") @db.VarChar(120)
|
||||
visitId String? @map("visit_id")
|
||||
assessmentId String? @map("assessment_id")
|
||||
userId String? @map("user_id")
|
||||
properties Json @default("{}")
|
||||
occurredAt DateTime @default(now()) @map("occurred_at")
|
||||
|
||||
visit BodyPortraitVisit? @relation(fields: [visitId], references: [id])
|
||||
assessment BodyPortraitAssessment? @relation(fields: [assessmentId], references: [id])
|
||||
user User? @relation(fields: [userId], references: [id])
|
||||
|
||||
@@index([name, occurredAt])
|
||||
@@index([userId, occurredAt])
|
||||
@@map("growth_events")
|
||||
}
|
||||
|
||||
model ProfessionalAssessmentSession {
|
||||
id String @id @default(uuid())
|
||||
userId String @map("user_id")
|
||||
kind String @db.VarChar(16)
|
||||
protocolVersion String @default("offline-v1") @map("protocol_version") @db.VarChar(32)
|
||||
recordedAt DateTime @db.Date @map("recorded_at")
|
||||
bookingId String? @map("booking_id")
|
||||
originAssessmentId String? @map("origin_assessment_id")
|
||||
observations Json
|
||||
subjectiveTension Float? @map("subjective_tension")
|
||||
coachSummary String @default("") @map("coach_summary") @db.VarChar(1000)
|
||||
trainingFocus String @default("") @map("training_focus") @db.VarChar(500)
|
||||
phaseGoal String @default("") @map("phase_goal") @db.VarChar(500)
|
||||
photoAngle String? @map("photo_angle") @db.VarChar(16)
|
||||
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])
|
||||
originAssessment BodyPortraitAssessment? @relation(fields: [originAssessmentId], references: [id])
|
||||
photos ProgressPhoto[]
|
||||
trainingPlans TrainingPlan[]
|
||||
|
||||
@@index([userId, recordedAt])
|
||||
@@map("professional_assessment_sessions")
|
||||
}
|
||||
|
||||
model TrainingPlan {
|
||||
id String @id @default(uuid())
|
||||
userId String @map("user_id")
|
||||
sessionId String? @map("session_id")
|
||||
title String @db.VarChar(80)
|
||||
status String @default("ACTIVE") @db.VarChar(16)
|
||||
weeks Int @default(12)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
session ProfessionalAssessmentSession? @relation(fields: [sessionId], references: [id])
|
||||
phases TrainingPlanPhase[]
|
||||
todos ReassessmentTodo[]
|
||||
shares GrowthShareCard[]
|
||||
|
||||
@@index([userId, createdAt])
|
||||
@@map("training_plans")
|
||||
}
|
||||
|
||||
model TrainingPlanPhase {
|
||||
id String @id @default(uuid())
|
||||
planId String @map("plan_id")
|
||||
name String @db.VarChar(40)
|
||||
lessonStart Int @map("lesson_start")
|
||||
lessonEnd Int @map("lesson_end")
|
||||
focus Json
|
||||
summary String @default("") @db.VarChar(300)
|
||||
sortOrder Int @default(0) @map("sort_order")
|
||||
|
||||
plan TrainingPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([planId])
|
||||
@@map("training_plan_phases")
|
||||
}
|
||||
|
||||
model ReassessmentTodo {
|
||||
id String @id @default(uuid())
|
||||
userId String @map("user_id")
|
||||
planId String @map("plan_id")
|
||||
lessonCheckpoint Int @map("lesson_checkpoint")
|
||||
dueAt DateTime @map("due_at")
|
||||
completedAt DateTime? @map("completed_at")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
plan TrainingPlan @relation(fields: [planId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([planId, lessonCheckpoint])
|
||||
@@index([userId, completedAt])
|
||||
@@map("reassessment_todos")
|
||||
}
|
||||
|
||||
model GrowthShareCard {
|
||||
id String @id @default(uuid())
|
||||
userId String @map("user_id")
|
||||
planId String? @map("plan_id")
|
||||
shareCode String @unique @map("share_code") @db.VarChar(12)
|
||||
title String @db.VarChar(80)
|
||||
caption String @db.VarChar(200)
|
||||
completedCount Int @map("completed_count")
|
||||
weeks Int @default(12)
|
||||
rows Json
|
||||
includePhotos Boolean @default(false) @map("include_photos")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
plan TrainingPlan? @relation(fields: [planId], references: [id])
|
||||
|
||||
@@index([userId, createdAt])
|
||||
@@map("growth_share_cards")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user