feat: group activities into boards with their own stages, like sales pipelines

Existing stages and activities move into a default board per environment; new activities pick a board in the form.
This commit is contained in:
2026-10-20 17:23:27 +03:30
parent 9127fa334b
commit e6aa4c64f0
11 changed files with 769 additions and 58 deletions
+26 -1
View File
@@ -224,6 +224,7 @@ model Organization {
reservationAppointments ReservationAppointment[]
leads Lead[]
leadStages LeadStage[]
activityBoards ActivityBoard[]
activityStages ActivityStage[]
activityTypeDefs ActivityTypeDef[]
leadEvents LeadEvent[]
@@ -686,10 +687,29 @@ model Deal {
}
/// مراحل/ستون‌های فعالیت (تب و کانبان) — kind وضعیت فعالیت داخل این مرحله را تعیین می‌کند
/// گروه فعالیت (مثل مسیر فروش برای معاملات): هر گروه ستون‌های خودش را دارد
model ActivityBoard {
id String @id @default(cuid())
organizationId String
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
name String
isDefault Boolean @default(false)
position Int @default(0)
stages ActivityStage[]
activities Activity[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([organizationId, name])
@@index([organizationId, position])
}
model ActivityStage {
id String @id @default(cuid())
organizationId String
organization Organization @relation(fields: [organizationId], references: [id], onDelete: Cascade)
boardId String
board ActivityBoard @relation(fields: [boardId], references: [id], onDelete: Cascade)
name String
position Int @default(0)
color String @default("green")
@@ -698,8 +718,9 @@ model ActivityStage {
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([organizationId, name])
@@unique([boardId, name])
@@index([organizationId, position])
@@index([boardId, position])
}
/// نوع فعالیت قابل تعریف توسط سازمان با فیلدهای اختصاصی
@@ -764,6 +785,9 @@ model Activity {
createdBy User? @relation("ActivityCreator", fields: [createdById], references: [id], onDelete: SetNull)
notes Note[]
routineTasks RoutineTask[]
/// گروه فعالیت؛ null = گروه پیش‌فرض محیط
boardId String?
board ActivityBoard? @relation(fields: [boardId], references: [id], onDelete: SetNull)
/// مرحله (ستون کانبان)؛ null یا مرحلهٔ ناهم‌نوع با status → اولین مرحلهٔ هم‌نوع
stageId String?
stage ActivityStage? @relation(fields: [stageId], references: [id], onDelete: SetNull)
@@ -781,6 +805,7 @@ model Activity {
updatedAt DateTime @updatedAt
@@index([stageId])
@@index([boardId])
@@index([typeDefId])
@@index([leadId])
@@index([organizationId, status, dueAt])