Add 17 features: My Work view, card copy/numbering, calendar, bulk ops, custom fields, automations, webhooks, invites, import/export, and more
Features implemented across 6 batches: - Batch A: Fix ColorPicker gradient sync, tenant custom logo, unarchive cards, board backgrounds - Batch B: My Work view, card copy/duplicate, card numbering (BOARD-123) - Batch C: Due date reminders (cron), card watching with notifications - Batch D: Bulk card operations, column sorting, calendar view - Batch E: Invite by link, board import/export (Pounce + Trello JSON) - Batch F: Webhooks with HMAC signing, custom fields, automation rules engine Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
+148
-21
@@ -13,6 +13,8 @@ model Tenant {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
name String
|
||||
slug String @unique
|
||||
logoUrl String? @map("logo_url")
|
||||
logoText String? @map("logo_text")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
@@ -23,6 +25,8 @@ model Tenant {
|
||||
categories Category[]
|
||||
boardTemplates BoardTemplate[]
|
||||
theme TenantTheme?
|
||||
invites TenantInvite[]
|
||||
webhooks Webhook[]
|
||||
|
||||
@@map("tenants")
|
||||
}
|
||||
@@ -70,6 +74,7 @@ model User {
|
||||
comments Comment[]
|
||||
activities Activity[]
|
||||
notifications Notification[]
|
||||
cardWatchers CardWatcher[]
|
||||
|
||||
@@unique([tenantId, email])
|
||||
@@map("users")
|
||||
@@ -108,14 +113,18 @@ model Board {
|
||||
background String?
|
||||
categoryId String? @map("category_id") @db.Uuid
|
||||
archived Boolean @default(false)
|
||||
cardPrefix String? @map("card_prefix")
|
||||
nextCardNum Int @default(1) @map("next_card_num")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||||
category Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
|
||||
columns Column[]
|
||||
members BoardMember[]
|
||||
activities Activity[]
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||||
category Category? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
|
||||
columns Column[]
|
||||
members BoardMember[]
|
||||
activities Activity[]
|
||||
customFieldDefs CustomFieldDef[]
|
||||
automationRules AutomationRule[]
|
||||
|
||||
@@map("boards")
|
||||
}
|
||||
@@ -150,23 +159,27 @@ model Column {
|
||||
// ─── Cards ────────────────────────────────────────────────────
|
||||
|
||||
model Card {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
columnId String @map("column_id") @db.Uuid
|
||||
title String
|
||||
description String?
|
||||
position String // Fractional index (lexicographic)
|
||||
dueDate DateTime? @map("due_date")
|
||||
archived Boolean @default(false)
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
columnId String @map("column_id") @db.Uuid
|
||||
title String
|
||||
description String?
|
||||
position String // Fractional index (lexicographic)
|
||||
dueDate DateTime? @map("due_date")
|
||||
archived Boolean @default(false)
|
||||
dueReminderSent Boolean @default(false) @map("due_reminder_sent")
|
||||
cardNumber Int? @map("card_number")
|
||||
createdAt DateTime @default(now()) @map("created_at")
|
||||
updatedAt DateTime @updatedAt @map("updated_at")
|
||||
|
||||
column Column @relation(fields: [columnId], references: [id], onDelete: Cascade)
|
||||
assignees CardAssignee[]
|
||||
labels CardLabel[]
|
||||
checklists Checklist[]
|
||||
comments Comment[]
|
||||
attachments Attachment[]
|
||||
activities Activity[]
|
||||
column Column @relation(fields: [columnId], references: [id], onDelete: Cascade)
|
||||
assignees CardAssignee[]
|
||||
labels CardLabel[]
|
||||
checklists Checklist[]
|
||||
comments Comment[]
|
||||
attachments Attachment[]
|
||||
activities Activity[]
|
||||
watchers CardWatcher[]
|
||||
customFieldValues CustomFieldValue[]
|
||||
|
||||
@@map("cards")
|
||||
}
|
||||
@@ -331,6 +344,120 @@ model BoardTemplate {
|
||||
@@map("board_templates")
|
||||
}
|
||||
|
||||
// ─── Card Watchers ───────────────────────────────────────────
|
||||
|
||||
model CardWatcher {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
cardId String @map("card_id") @db.Uuid
|
||||
userId String @map("user_id") @db.Uuid
|
||||
|
||||
card Card @relation(fields: [cardId], references: [id], onDelete: Cascade)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([cardId, userId])
|
||||
@@map("card_watchers")
|
||||
}
|
||||
|
||||
// ─── Tenant Invites ──────────────────────────────────────────
|
||||
|
||||
model TenantInvite {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
tenantId String @map("tenant_id") @db.Uuid
|
||||
code String @unique
|
||||
role TenantRole @default(MEMBER)
|
||||
expiresAt DateTime @map("expires_at")
|
||||
createdBy String @map("created_by") @db.Uuid
|
||||
usedCount Int @default(0) @map("used_count")
|
||||
maxUses Int? @map("max_uses")
|
||||
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("tenant_invites")
|
||||
}
|
||||
|
||||
// ─── Webhooks ────────────────────────────────────────────────
|
||||
|
||||
model Webhook {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
tenantId String @map("tenant_id") @db.Uuid
|
||||
url String
|
||||
events String[]
|
||||
secret String
|
||||
active Boolean @default(true)
|
||||
|
||||
tenant Tenant @relation(fields: [tenantId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("webhooks")
|
||||
}
|
||||
|
||||
// ─── Custom Fields ───────────────────────────────────────────
|
||||
|
||||
enum CustomFieldType {
|
||||
TEXT
|
||||
NUMBER
|
||||
DATE
|
||||
SELECT
|
||||
MULTI_SELECT
|
||||
}
|
||||
|
||||
model CustomFieldDef {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
boardId String @map("board_id") @db.Uuid
|
||||
name String
|
||||
type CustomFieldType
|
||||
options Json? // For SELECT/MULTI_SELECT: string[]
|
||||
position String
|
||||
|
||||
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
|
||||
values CustomFieldValue[]
|
||||
|
||||
@@map("custom_field_defs")
|
||||
}
|
||||
|
||||
model CustomFieldValue {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
cardId String @map("card_id") @db.Uuid
|
||||
fieldId String @map("field_id") @db.Uuid
|
||||
value String
|
||||
|
||||
card Card @relation(fields: [cardId], references: [id], onDelete: Cascade)
|
||||
field CustomFieldDef @relation(fields: [fieldId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([cardId, fieldId])
|
||||
@@map("custom_field_values")
|
||||
}
|
||||
|
||||
// ─── Automation Rules ────────────────────────────────────────
|
||||
|
||||
enum AutomationTrigger {
|
||||
CARD_MOVED
|
||||
DUE_PASSED
|
||||
LABEL_ADDED
|
||||
CARD_CREATED
|
||||
}
|
||||
|
||||
enum AutomationAction {
|
||||
ADD_LABEL
|
||||
REMOVE_LABEL
|
||||
ASSIGN
|
||||
SET_DUE
|
||||
MOVE_TO_COLUMN
|
||||
}
|
||||
|
||||
model AutomationRule {
|
||||
id String @id @default(uuid()) @db.Uuid
|
||||
boardId String @map("board_id") @db.Uuid
|
||||
trigger AutomationTrigger
|
||||
triggerConfig Json? @map("trigger_config")
|
||||
action AutomationAction
|
||||
actionConfig Json? @map("action_config")
|
||||
active Boolean @default(true)
|
||||
|
||||
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@map("automation_rules")
|
||||
}
|
||||
|
||||
// ─── Tenant Branding & Theming ───────────────────────────────
|
||||
|
||||
model TenantTheme {
|
||||
|
||||
Reference in New Issue
Block a user