Files
HiveGrid-Wireframes/hivegrid-cloud/prisma/schema/tasks.prisma
T

105 lines
3.3 KiB
Plaintext

// P4 Tasks (AK-P4b) — lightweight cross-cutting task module.
//
// AD-21: one self-contained schema file per module. `tenantId` /
// `createdByUserId` / `assignedToUserId` / `assignedToGroupId` are intentionally
// BARE String scalars (no `@relation`) so this file has zero merge-conflict
// surface against `core.prisma`/`accounts.prisma` (no back-relation fields on
// Tenant/User/Group needed). Referential integrity is carried by app-level
// scoping (taskService + taskAccess) plus the RLS policies from the merge
// migration (see local/AK-P4b-merge-migration.sql).
//
// Assignment rule (DoD 2): a task is assigned to EXACTLY ONE of a user or a
// group; default = creator. Enforced in the service layer and by a DB CHECK
// constraint (num_nonnulls(...) = 1) added in the merge migration.
//
// Entity linking: the primary "this task is about X" association lives inline on
// the Task (`linkedEntityType`/`linkedEntityId`). The generic, reusable
// cross-entity link table is `EntityLink` (entityLinks.prisma, Gate W1); wiring
// tasks to concrete CRM entities happens in P6.
enum TaskStatus {
open
in_progress
blocked
done
cancelled
}
enum TaskPriority {
low
normal
high
urgent
}
enum TaskSource {
manual
chat
form_submission
automation
api
}
enum TaskEntityType {
contact
company
lead
deal
project
user
order
appointment
}
/// A task, scoped per tenant. Soft-delete via `archivedAt` (archive flag). A
/// completed task (`status = done`, `completedAt` set) is auto-archived 30 days
/// later by a maintenance cron.
model Task {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
tenantId String
createdByUserId String
title String
description String? // markdown
status TaskStatus @default(open)
priority TaskPriority @default(normal)
deadline DateTime?
// Assignment: EXACTLY ONE of user/group (DB CHECK in merge migration);
// default = creator (filled by the service when neither is provided).
assignedToUserId String?
assignedToGroupId String?
// Inline primary entity association (polymorphic) — "this task is about X".
linkedEntityType TaskEntityType?
linkedEntityId String?
source TaskSource @default(manual)
sourceRef String? // marker/link back to origin (chat msg / form submission / automation run)
completedAt DateTime?
isDemoData Boolean @default(false)
archivedAt DateTime?
watchers TaskWatcher[]
@@index([tenantId, archivedAt, status, deadline])
@@index([tenantId, assignedToUserId])
@@index([tenantId, assignedToGroupId])
@@index([tenantId, createdByUserId])
@@index([tenantId, linkedEntityType, linkedEntityId])
@@index([tenantId, status, completedAt]) // for the 30-day archive sweep
}
/// A user watching a task (M:N). Watchers receive reminder notifications in
/// addition to the assignee.
model TaskWatcher {
id String @id @default(cuid())
createdAt DateTime @default(now())
tenantId String
taskId String
userId String
task Task @relation(fields: [taskId], references: [id], onDelete: Cascade)
@@unique([taskId, userId])
@@index([tenantId, userId])
}