Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
H
hrsystem
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
hrsystem
Commits
ff7f1d41
Commit
ff7f1d41
authored
Apr 02, 2026
by
Administrator
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Update prisma/schema.prisma via Son of Anton
parent
0f56e115
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
852 additions
and
1463 deletions
+852
-1463
schema.prisma
prisma/schema.prisma
+852
-1463
No files found.
prisma/schema.prisma
View file @
ff7f1d41
//
============================================================
//
AL
-
ARCADE
HR
PLATFORM
v3
.0
—
"THE GRIND"
//
Complete
Prisma
Schema
—
ALL
modules
,
ALL
phases
//
============================================================
//
This
is
your
main
Prisma
schema
file
.
//
Since
we
're using multi-file schemas, ensure your package.json
// has the correct prisma configuration.
generator client {
provider = "prisma-client-js"
previewFeatures
=
[
"
fullTextSearch"
,
"fullTextIndex
"
]
previewFeatures = ["
multiSchema", "prismaSchemaFolder
"]
}
datasource db {
...
...
@@ -13,51 +12,34 @@ datasource db {
url = env("DATABASE_URL")
}
//
============================================
================
// ============================================
// ENUMS
//
============================================
================
// ============================================
enum Role {
SUPER_ADMIN
ADMIN
TEAM_LEAD
PROJECT_LEADER
CONTRACTOR
}
enum ContractorType {
FULL_TIME
PART_TIME
PROJECT_BASED
INTERN
}
enum
UserStatus
{
INVITED
enum ContractorStatus {
ONBOARDING
ACTIVE
ON_PIP
SUSPENDED
OFFBOARDING
OFFBOARDED
}
enum
InviteStatus
{
PENDING
ACCEPTED
EXPIRED
REVOKED
}
enum
BoardVisibility
{
PUBLIC
PRIVATE
TEAM
}
enum
BoardMemberRole
{
OWNER
ADMIN
MEMBER
VIEWER
enum DayType {
IN_OFFICE
REMOTE
OFF
}
enum CardPriority {
...
...
@@ -68,163 +50,137 @@ enum CardPriority {
NONE
}
enum
DeductionType
{
MANUAL
AUTO_LATE_REPORT
AUTO_MISSED_REPORT
AUTO_PIP
PRESET
}
enum
DeductionStatus
{
PENDING
APPROVED
REJECTED
APPEALED
REVERSED
}
enum
AdjustmentType
{
ADVANCE
REIMBURSEMENT
BONUS
CORRECTION
OTHER
enum ColumnType {
BACKLOG
TODO
DOING
FROZEN
IN_REVIEW
DONE
CUSTOM
}
enum
AdjustmentStatus
{
PENDING
APPROVED
REJECTED
enum DeductionCategory {
A
B
C
D
}
enum
BountyStatus
{
PENDING
EARNED
PAID
enum DeductionStatus {
DRAFT
PENDING_ADMIN_REVIEW
PENDING_ACKNOWLEDGMENT
PENDING_RESPONSE
UPHELD
REDUCED
DISMISSED
AUTO_APPLIED
CANCELLED
}
enum
Payroll
Status
{
enum
Report
Status {
DRAFT
CALCULATING
REVIEW
SUBMITTED
LATE
APPROVED
PAID
CANCELLED
}
enum
NotificationType
{
PASSIVE
IMPORTANT
BLOCKING
}
enum
NotificationCategory
{
CARD
BOARD
SALARY
DEDUCTION
BOUNTY
ADJUSTMENT
PAYROLL
REPORT
EVALUATION
PIP
MESSAGE
MEETING
NOTICE
POLICY
ONBOARDING
UNAVAILABILITY
SCHEDULE
SYSTEM
}
enum
ConversationType
{
DIRECT
GROUP
}
enum
MessageType
{
TEXT
FILE
SYSTEM
AUTO_APPROVED
FLAGGED_VAGUE
FLAGGED_INCONSISTENT
REVISION_REQUESTED
AMENDED
UNREPORTED
}
enum
ReportStatus
{
DRAFT
enum PayrollStatus {
PENDING_CALCULATION
CALCULATED
UNDER_REVIEW
SUBMITTED
APPROVED
REJECTED
AMENDMENT_REQUESTED
PROCESSING
PAID
}
enum EvaluationStatus {
DRAFT
IN_PROGRESS
COMP
LET
ED
PENDING_TECHNICAL
PENDING_PROFESSIONAL
COMP
IL
ED
ACKNOWLEDGED
RESPONDED
}
enum
P
IP
Status
{
enum P
ip
Status {
ACTIVE
PASSED
FAILED
EXTENDED
CANCELLED
}
enum LearningGoalStatus {
NOT_STARTED
IN_PROGRESS
COMPLETED
CANCELLED
ACTIVE
OVERDUE
PASSED
FAILED
EXTENDED
}
enum
UnavailabilityType
{
VACATION
SICK
PERSONAL
EMERGENCY
enum NotificationType {
BLOCKING
IMPORTANT
INFORMATIONAL
}
enum NoticeType {
GENERAL_ANNOUNCEMENT
OFFICIAL_WARNING
POLICY_UPDATE
CUSTOM
}
enum AdjustmentType {
POSITIVE
NEGATIVE
}
enum AdjustmentCategory {
ADVANCE
REIMBURSEMENT
BONUS
CORRECTION
LOAN
OTHER
}
enum
Reques
tStatus
{
PENDING
enum
Adjustmen
tStatus {
PENDING
_APPROVAL
APPROVED
REJECTED
CANCELLED
}
enum
MeetingStatus
{
SCHEDULED
IN_PROGRESS
COMPLETED
CANCELLED
}
enum
ContractStatus
{
DRAFT
enum InviteStatus {
ACTIVE
USED
EXPIRED
TERMINAT
ED
REVOK
ED
}
enum
OffboardingStatus
{
PENDING
IN_PROGRESS
enum MeetingStatus {
SCHEDULED
COMPLETED
CANCELLED
}
enum
WebhookStatus
{
ACTIVE
INACTIVE
FAILED
enum UnavailabilityReason {
PERSONAL
MEDICAL
RELIGIOUS
EMERGENCY
OTHER
}
enum
Recurrence
Pattern
{
enum Recurrence
Type
{
DAILY
WEEKLY
BIWEEKLY
...
...
@@ -232,501 +188,321 @@ enum RecurrencePattern {
CUSTOM
}
enum
AuditAction
{
CREATE
UPDATE
DELETE
ARCHIVE
RESTORE
LOGIN
LOGOUT
PASSWORD_RESET
PASSWORD_CHANGE
ROLE_CHANGE
STATUS_CHANGE
APPROVE
REJECT
SUBMIT
MOVE
ASSIGN
UNASSIGN
LOCK
UNLOCK
ACKNOWLEDGE
BULK_ACTION
EXPORT
IMPORT
SETTINGS_CHANGE
GENERATE
SEND
}
//
============================================================
//
AUTH
&
USERS
//
============================================================
enum LabelScope {
ORGANIZATION
BOARD
}
enum ApiKeyScope {
READ_ONLY
READ_WRITE
ADMIN
}
enum ConversationType {
DIRECT
GROUP
}
enum TerminationType {
VOLUNTARY
FOR_CAUSE
MUTUAL
CONTRACT_EXPIRY
}
// ============================================
// CORE MODELS
// ============================================
model User {
id
String
@
id
@
default
(
uuid
())
email
String
@
unique
username
String
@
unique
passwordHash
String
firstName
String
lastName
String
displayName
String
?
avatar
String
?
role
Role
@
default
(
CONTRACTOR
)
contractorType
ContractorType
?
status
UserStatus
@
default
(
INVITED
)
department
String
?
title
String
?
phone
String
?
timezone
String
@
default
(
"Africa/Cairo"
)
bio
String
?
dateOfBirth
DateTime
?
startDate
DateTime
?
lastLoginAt
DateTime
?
isOnline
Boolean
@
default
(
false
)
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
id String @id @default(uuid())
username String @unique
passwordHash String
firstName String
lastName String
nameArabic String?
nationalId String? @unique
dateOfBirth DateTime?
phone String?
phoneSecondary String?
address String?
avatar String?
role Role @default(CONTRACTOR)
contractorType ContractorType?
status ContractorStatus @default(ONBOARDING)
weeklySchedule Json?
baseSalaryPiasters Int?
actualSalaryPiasters Int?
bankName String?
bankAccountNumber String?
bankAccountHolderName String?
emergencyContactName String?
emergencyContactPhone String?
emergencyContactRelationship String?
currentStreak Int @default(0)
bestStreak Int @default(0)
forcePasswordChange Boolean @default(false)
activatedAt DateTime?
contractSignedAt DateTime?
lastLoginAt DateTime?
loginAttempts Int @default(0)
lockedUntil DateTime?
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
//
Relations
—
Auth
&
Sessions
// Relations
boards BoardMember[]
assignedCards CardAssignee[]
watchedCards CardWatcher[]
createdCards Card[] @relation("CardCreator")
comments Comment[]
attachments Attachment[]
reports DailyReport[] @relation("ReportAuthor")
reviewedReports DailyReport[] @relation("ReportReviewer")
deductions Deduction[] @relation("DeductionTarget")
initiatedDeductions Deduction[] @relation("DeductionInitiator")
reviewedDeductions Deduction[] @relation("DeductionReviewer")
bountyPayouts BountyPayout[]
adjustments Adjustment[] @relation("AdjustmentTarget")
createdAdjustments Adjustment[] @relation("AdjustmentCreator")
reviewedAdjustments Adjustment[] @relation("AdjustmentReviewer")
evaluations Evaluation[] @relation("EvaluationTarget")
techEvaluator Evaluation[] @relation("TechEvaluator")
profEvaluator Evaluation[] @relation("ProfEvaluator")
pips Pip[] @relation("PipTarget")
createdPips Pip[] @relation("PipCreator")
learningGoals LearningGoal[] @relation("GoalTarget")
createdGoals LearningGoal[] @relation("GoalCreator")
unavailability Unavailability[]
scheduleRequests ScheduleChangeRequest[] @relation("ScheduleRequester")
reviewedSchedules ScheduleChangeRequest[] @relation("ScheduleReviewer")
conversations ConversationParticipant[]
sentMessages Message[]
notifications Notification[]
noticeAcknowledgments NoticeAcknowledgment[]
policyAcknowledgments PolicyAcknowledgment[]
contracts Contract[]
meetings MeetingInvitee[]
createdMeetings Meeting[] @relation("MeetingCreator")
invites Invite[]
refreshTokens RefreshToken[]
payrollLines PayrollLine[]
createdNotices Notice[]
sessions Session[]
passwordResetTokens
PasswordResetToken
[]
//
Relations
—
Onboarding
sentInvites
Invite
[]
@
relation
(
"InviteSender"
)
receivedInvite
Invite
?
@
relation
(
"InviteRecipient"
)
onboardingProgress
ContractorOnboarding
?
//
Relations
—
Boards
&
Cards
ownedBoards
Board
[]
@
relation
(
"BoardCreator"
)
boardMemberships
BoardMember
[]
createdCards
Card
[]
@
relation
(
"CardCreator"
)
cardAssignments
CardAssignee
[]
cardWatches
CardWatcher
[]
cardComments
CardComment
[]
cardActivities
CardActivity
[]
@
relation
(
"CardActivityActor"
)
lockedCards
Card
[]
@
relation
(
"CardLocker"
)
//
Relations
—
Financial
contractorSalaries
ContractorSalary
[]
@
relation
(
"SalaryContractor"
)
createdSalaries
ContractorSalary
[]
@
relation
(
"SalaryCreator"
)
earnedBounties
Bounty
[]
@
relation
(
"BountyContractor"
)
createdBounties
Bounty
[]
@
relation
(
"BountyCreator"
)
receivedDeductions
Deduction
[]
@
relation
(
"DeductionContractor"
)
createdDeductions
Deduction
[]
@
relation
(
"DeductionCreator"
)
approvedDeductions
Deduction
[]
@
relation
(
"DeductionApprover"
)
reversedDeductions
Deduction
[]
@
relation
(
"DeductionReverser"
)
receivedAdjustments
SalaryAdjustment
[]
@
relation
(
"AdjustmentContractor"
)
createdAdjustments
SalaryAdjustment
[]
@
relation
(
"AdjustmentCreator"
)
approvedAdjustments
SalaryAdjustment
[]
@
relation
(
"AdjustmentApprover"
)
payrollItems
PayrollItem
[]
generatedPayrolls
PayrollPeriod
[]
@
relation
(
"PayrollGenerator"
)
approvedPayrolls
PayrollPeriod
[]
@
relation
(
"PayrollApprover"
)
//
Relations
—
Communication
conversationParticipations
ConversationParticipant
[]
sentMessages
Message
[]
createdNotices
Notice
[]
@
relation
(
"NoticeCreator"
)
createdPolicies
Policy
[]
@
relation
(
"PolicyCreator"
)
policyAcknowledgments
PolicyAcknowledgment
[]
//
Relations
—
Notifications
notifications
Notification
[]
notificationPreferences
NotificationPreference
[]
//
Relations
—
Reports
dailyReports
DailyReport
[]
@
relation
(
"ReportContractor"
)
reviewedReports
DailyReport
[]
@
relation
(
"ReportReviewer"
)
//
Relations
—
Performance
evaluationsReceived
Evaluation
[]
@
relation
(
"EvaluationContractor"
)
evaluationsGiven
Evaluation
[]
@
relation
(
"EvaluationEvaluator"
)
createdEvalTemplates
EvaluationTemplate
[]
pipsReceived
PIP
[]
@
relation
(
"PIPContractor"
)
pipsManaged
PIP
[]
@
relation
(
"PIPManager"
)
learningGoals
LearningGoal
[]
competencyAssessments
CompetencyAssessment
[]
@
relation
(
"AssessmentContractor"
)
givenAssessments
CompetencyAssessment
[]
@
relation
(
"AssessmentAssessor"
)
//
Relations
—
Time
&
Scheduling
unavailabilityRequests
UnavailabilityRequest
[]
@
relation
(
"UnavailabilityContractor"
)
reviewedUnavailabilities
UnavailabilityRequest
[]
@
relation
(
"UnavailabilityReviewer"
)
scheduleChangeRequests
ScheduleChangeRequest
[]
@
relation
(
"ScheduleChangeContractor"
)
reviewedScheduleChanges
ScheduleChangeRequest
[]
@
relation
(
"ScheduleChangeReviewer"
)
workSchedule
WorkSchedule
?
//
Relations
—
Meetings
createdMeetings
Meeting
[]
@
relation
(
"MeetingCreator"
)
meetingParticipations
MeetingParticipant
[]
//
Relations
—
Contracts
&
Offboarding
contracts
Contract
[]
offboardingProcesses
OffboardingProcess
[]
@
relation
(
"OffboardingContractor"
)
initiatedOffboardings
OffboardingProcess
[]
@
relation
(
"OffboardingInitiator"
)
//
Relations
—
Admin
apiKeys
ApiKey
[]
createdWebhooks
Webhook
[]
//
Relations
—
Notes
&
Activity
privateNotesAbout
PrivateNote
[]
@
relation
(
"NoteSubject"
)
privateNotesAuthored
PrivateNote
[]
@
relation
(
"NoteAuthor"
)
activityFeedItems
ActivityFeedItem
[]
@
relation
(
"ActivityActor"
)
uploadedFiles
File
[]
//
Relations
—
Templates
createdBoardTemplates
BoardTemplate
[]
createdCardTemplates
CardTemplate
[]
@@
index
([
email
])
@@index([username])
@@
index
([
role
])
@@index([status])
@@index([role])
@@index([contractorType])
@@index([deletedAt])
@@
index
([
department
])
@@
map
(
"users"
)
}
model
Session
{
id
String
@
id
@
default
(
uuid
())
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
token
String
@
unique
refreshToken
String
@
unique
ipAddress
String
?
userAgent
String
?
expiresAt
DateTime
lastActiveAt
DateTime
@
default
(
now
())
createdAt
DateTime
@
default
(
now
())
model RefreshToken {
id String @id @default(uuid())
token String @unique
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
expiresAt DateTime
createdAt DateTime @default(now())
@@index([userId])
@@
index
([
token
])
@@index([expiresAt])
@@
map
(
"sessions"
)
}
model
PasswordResetToke
n
{
id
String
@
id
@
default
(
uuid
())
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
token
String
@
unique
expiresAt
DateTime
usedAt
DateTime
?
createdAt
DateTime
@
default
(
now
())
model
Sessio
n {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
ipAddress String?
userAgent String?
lastActivity DateTime @default(now())
createdAt DateTime @default(now())
@@
index
([
token
])
@@index([userId])
@@
map
(
"password_reset_tokens"
)
}
//
============================================================
//
SYSTEM
SETTINGS
//
============================================================
model
SystemSetting
{
model Setting {
id String @id @default(uuid())
key String @unique
value Json
description String?
category
String
@
default
(
"general"
)
createdAt
DateTime
@
default
(
now
())
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
@@index([key])
@@
index
([
category
])
@@
map
(
"system_settings"
)
}
//
============================================================
//
AUDIT
TRAIL
(
IMMUTABLE
)
//
============================================================
model
AuditLog
{
id
String
@
id
@
default
(
uuid
())
userId
String
?
action
AuditAction
entityType
String
entityId
String
?
oldValue
Json
?
newValue
Json
?
metadata
Json
?
ipAddress
String
?
userAgent
String
?
createdAt
DateTime
@
default
(
now
())
//
NO
updatedAt
.
NO
deletedAt
.
IMMUTABLE
.
model AuditTrail {
id String @id @default(uuid())
userId String?
action String
entityType String
entityId String?
method String?
url String?
before Json?
after Json?
ipAddress String?
userAgent String?
createdAt DateTime @default(now())
@@index([userId])
@@
index
([
entityType
,
entityId
])
@@index([entityType])
@@index([action])
@@index([createdAt])
@@
map
(
"audit_logs"
)
}
//
============================================================
//
ONBOARDING
//
============================================================
model
Invite
{
id
String
@
id
@
default
(
uuid
())
email
String
role
Role
@
default
(
CONTRACTOR
)
senderId
String
sender
User
@
relation
(
"InviteSender"
,
fields
:
[
senderId
],
references
:
[
id
])
recipientId
String
?
@
unique
recipient
User
?
@
relation
(
"InviteRecipient"
,
fields
:
[
recipientId
],
references
:
[
id
])
token
String
@
unique
status
InviteStatus
@
default
(
PENDING
)
message
String
?
expiresAt
DateTime
acceptedAt
DateTime
?
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
email
])
@@
index
([
token
])
@@
index
([
status
])
@@
map
(
"invites"
)
}
model
OnboardingChecklist
{
id
String
@
id
@
default
(
uuid
())
name
String
description
String
?
role
Role
@
default
(
CONTRACTOR
)
isActive
Boolean
@
default
(
true
)
items
OnboardingChecklistItem
[]
contractors
ContractorOnboarding
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
@@
map
(
"onboarding_checklists"
)
}
model
OnboardingChecklistItem
{
id
String
@
id
@
default
(
uuid
())
checklistId
String
checklist
OnboardingChecklist
@
relation
(
fields
:
[
checklistId
],
references
:
[
id
],
onDelete
:
Cascade
)
title
String
description
String
?
order
Int
isRequired
Boolean
@
default
(
true
)
progressItems
ContractorOnboardingItem
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
checklistId
])
@@
map
(
"onboarding_checklist_items"
)
}
model
ContractorOnboarding
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
@
unique
contractor
User
@
relation
(
fields
:
[
contractorId
],
references
:
[
id
],
onDelete
:
Cascade
)
checklistId
String
checklist
OnboardingChecklist
@
relation
(
fields
:
[
checklistId
],
references
:
[
id
])
completedAt
DateTime
?
items
ContractorOnboardingItem
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
contractorId
])
@@
map
(
"contractor_onboardings"
)
}
model
ContractorOnboardingItem
{
id
String
@
id
@
default
(
uuid
())
onboardingId
String
onboarding
ContractorOnboarding
@
relation
(
fields
:
[
onboardingId
],
references
:
[
id
],
onDelete
:
Cascade
)
checklistItemId
String
checklistItem
OnboardingChecklistItem
@
relation
(
fields
:
[
checklistItemId
],
references
:
[
id
])
isCompleted
Boolean
@
default
(
false
)
completedAt
DateTime
?
notes
String
?
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
unique
([
onboardingId
,
checklistItemId
])
@@
map
(
"contractor_onboarding_items"
)
}
//
============================================
================
// ============================================
// BOARDS & KANBAN
//
============================================
================
// ============================================
model Board {
id
String
@
id
@
default
(
uuid
())
name
String
description
String
?
visibility
BoardVisibility
@
default
(
TEAM
)
createdById
String
createdBy
User
@
relation
(
"BoardCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
prefix
String
?
color
String
?
icon
String
?
isArchived
Boolean
@
default
(
false
)
archivedAt
DateTime
?
columns
Column
[]
members
BoardMember
[]
labels
Label
[]
cards
Card
[]
id String @id @default(uuid())
name String
description String?
key String @unique
visibility String @default("PRIVATE")
icon String?
color String?
allowContractorCreation Boolean @default(true)
autoArchiveDoneCardsDays Int @default(30)
isArchived Boolean @default(false)
nextCardNumber Int @default(1)
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
columns BoardColumn[]
members BoardMember[]
cards Card[]
labels Label[] @relation("BoardLabels")
savedFilters SavedFilter[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
@@
index
([
createdById
])
@@
index
([
visibility
])
@@
index
([
deletedAt
])
@@index([key])
@@index([isArchived])
@@
map
(
"boards"
)
@@
index([deletedAt]
)
}
model
Board
Member
{
id
String
@
id
@
default
(
uuid
())
model Board
Column
{
id String @id @default(uuid())
boardId String
board
Board
@
relation
(
fields
:
[
boardId
],
references
:
[
id
],
onDelete
:
Cascade
)
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
role
BoardMemberRole
@
default
(
MEMBER
)
joinedAt
DateTime
@
default
(
now
())
@@
unique
([
boardId
,
userId
])
@@
index
([
userId
])
@@
map
(
"board_members"
)
}
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
name String
type ColumnType
icon String?
position Int
wipLimit Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model
BoardTemplate
{
id
String
@
id
@
default
(
uuid
())
name
String
description
String
?
structure
Json
//
{
columns
:
[...],
labels
:
[...]
}
createdById
String
createdBy
User
@
relation
(
fields
:
[
createdById
],
references
:
[
id
])
isPublic
Boolean
@
default
(
false
)
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
cards Card[]
@@
map
(
"board_templates"
)
@@index([boardId])
@@index([type])
}
model
Column
{
id
String
@
id
@
default
(
uuid
())
boardId
String
board
Board
@
relation
(
fields
:
[
boardId
],
references
:
[
id
],
onDelete
:
Cascade
)
name
String
position
Float
color
String
?
wipLimit
Int
?
isDone
Boolean
@
default
(
false
)
cards
Card
[]
model BoardMember {
id String @id @default(uuid())
boardId String
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
role String @default("MEMBER")
createdAt DateTime @default(now())
updatedAt
DateTime
@
updatedAt
@@unique([boardId, userId])
@@index([boardId])
@@
index
([
boardId
,
position
])
@@
map
(
"columns"
)
@@index([userId])
}
model Label {
id
String
@
id
@
default
(
uuid
())
boardId
String
board
Board
@
relation
(
fields
:
[
boardId
],
references
:
[
id
],
onDelete
:
Cascade
)
name
String
color
String
cards
CardLabel
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
id String @id @default(uuid())
name String
color String
textColor String @default("#FFFFFF")
scope LabelScope @default(ORGANIZATION)
boardId String?
board Board? @relation("BoardLabels", fields: [boardId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
cards CardLabel[]
@@index([scope])
@@index([boardId])
@@
map
(
"labels"
)
}
//
============================================================
//
CARDS
//
============================================================
model Card {
id
String
@
id
@
default
(
uuid
())
title
String
description
String
?
id String @id @default(uuid())
boardId String
board
Board
@
relation
(
fields
:
[
boardId
],
references
:
[
id
],
onDelete
:
Cascade
)
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
columnId String
column
Column
@
relation
(
fields
:
[
columnId
],
references
:
[
id
])
position
Float
priority
CardPriority
@
default
(
NONE
)
column BoardColumn @relation(fields: [columnId], references: [id], onDelete: Cascade)
cardNumber String
title String
description String?
priority CardPriority @default(NONE)
position Float @default(0)
dueDate DateTime?
startDate
DateTime
?
estimatedHours Float?
actualHours
Float
?
bountyPiasters
Int
@
default
(
0
)
coverImage
String
?
isLocked
Boolean
@
default
(
false
)
lockedById
String
?
lockedBy
User
?
@
relation
(
"CardLocker"
,
fields
:
[
lockedById
],
references
:
[
id
])
lockedAt
DateTime
?
parentCardId
String
?
parentCard
Card
?
@
relation
(
"CardSubtasks"
,
fields
:
[
parentCardId
],
references
:
[
id
])
subtasks
Card
[]
@
relation
(
"CardSubtasks"
)
createdById
String
createdBy
User
@
relation
(
"CardCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
bountyPiasters Int @default(0)
bountyPaidOut Boolean @default(false)
frozenReason String?
version Int @default(1)
isArchived Boolean @default(false)
completedAt DateTime?
archivedAt
DateTime
?
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
firstDoingAt DateTime?
totalFrozenMs Int @default(0)
createdById String
createdBy User @relation("CardCreator", fields: [createdById], references: [id])
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
//
Relations
assignees
CardAssignee
[]
watchers
CardWatcher
[]
labels
CardLabel
[]
comments
CardComment
[]
checklists
Checklist
[]
attachments
CardAttachment
[]
activities
CardActivity
[]
bounties
Bounty
[]
reportEntries
DailyReportEntry
[]
assignees CardAssignee[]
watchers CardWatcher[]
labels CardLabel[]
comments Comment[]
attachments Attachment[]
checklists Checklist[]
bountyPayouts BountyPayout[]
deductions Deduction[]
@@index([boardId])
@@index([columnId])
@@
index
([
c
reatedById
])
@@
index
([
priority
])
@@index([c
ardNumber
])
@@index([
isArchived
])
@@index([dueDate])
@@index([deletedAt])
@@
index
([
boardId
,
columnId
,
position
])
@@
index
([
parentCardId
])
@@
map
(
"cards"
)
@@index([createdById])
}
model CardAssignee {
id
String
@
id
@
default
(
uuid
())
cardId
String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
assign
edAt
DateTime
@
default
(
now
())
id
String
@id @default(uuid())
cardId String
card
Card
@relation(fields: [cardId], references: [id], onDelete: Cascade)
userId String
user
User
@relation(fields: [userId], references: [id], onDelete: Cascade)
creat
edAt DateTime @default(now())
@@unique([cardId, userId])
@@index([cardId])
@@index([userId])
@@
map
(
"card_assignees"
)
}
model CardWatcher {
id
String
@
id
@
default
(
uuid
())
cardId
String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
addedAt
DateTime
@
default
(
now
())
id
String
@id @default(uuid())
cardId String
card
Card
@relation(fields: [cardId], references: [id], onDelete: Cascade)
userId String
user
User
@relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt
DateTime @default(now())
@@unique([cardId, userId])
@@index([cardId])
@@index([userId])
@@
map
(
"card_watchers"
)
}
model CardLabel {
...
...
@@ -737,359 +513,374 @@ model CardLabel {
label Label @relation(fields: [labelId], references: [id], onDelete: Cascade)
@@unique([cardId, labelId])
@@
map
(
"card_labels"
)
@@index([cardId])
@@index([labelId])
}
model
CardComment
{
id
String
@
id
@
default
(
uuid
())
cardId
String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
authorId
String
author
User
@
relation
(
fields
:
[
authorId
],
references
:
[
id
])
content
String
isEdited
Boolean
@
default
(
false
)
parentId
String
?
parent
CardComment
?
@
relation
(
"CommentReplies"
,
fields
:
[
parentId
],
references
:
[
id
])
replies
CardComment
[]
@
relation
(
"CommentReplies"
)
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
// ============================================
// COMMENTS, CHECKLISTS, ATTACHMENTS
// ============================================
model Comment {
id String @id @default(uuid())
cardId String
card Card @relation(fields: [cardId], references: [id], onDelete: Cascade)
authorId String
author User @relation(fields: [authorId], references: [id])
content String
editedAt DateTime?
editableUntil DateTime?
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([cardId])
@@index([authorId])
@@
index
([
parentId
])
@@
map
(
"card_comments"
)
}
model Checklist {
id
String
@
id
@
default
(
uuid
())
cardId
String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
title
String
position
Float
items
ChecklistItem
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
id String @id @default(uuid())
cardId String
card Card @relation(fields: [cardId], references: [id], onDelete: Cascade)
name String
position Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
items ChecklistItem[]
@@index([cardId])
@@
map
(
"checklists"
)
}
model ChecklistItem {
id String @id @default(uuid())
checklistId String
checklist Checklist @relation(fields: [checklistId], references: [id], onDelete: Cascade)
title
String
isCompleted
Boolean
@
default
(
false
)
completedAt
DateTime
?
assigneeId
String
?
position
Float
dueDate
DateTime
?
text String
isChecked Boolean @default(false)
position Int @default(0)
checkedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([checklistId])
@@
map
(
"checklist_items"
)
}
model
CardAttachment
{
id
String
@
id
@
default
(
uuid
())
cardId
String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
fileId
String
file
File
@
relation
(
fields
:
[
fileId
],
references
:
[
id
])
createdAt
DateTime
@
default
(
now
())
@@
index
([
cardId
])
@@
map
(
"card_attachments"
)
}
model
CardActivity
{
id
String
@
id
@
default
(
uuid
())
cardId
String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
actorId
String
actor
User
@
relation
(
"CardActivityActor"
,
fields
:
[
actorId
],
references
:
[
id
])
action
String
//
"moved"
,
"assigned"
,
"commented"
,
"priority_changed"
,
etc
.
details
Json
?
//
{
from
:
"To Do"
,
to
:
"In Progress"
}
createdAt
DateTime
@
default
(
now
())
model Attachment {
id String @id @default(uuid())
cardId String?
card Card? @relation(fields: [cardId], references: [id], onDelete: Cascade)
uploadedById String
uploadedBy User @relation(fields: [uploadedById], references: [id])
fileName String
fileSize Int
mimeType String
storagePath String
entityType String @default("card")
entityId String?
createdAt DateTime @default(now())
@@index([cardId])
@@
index
([
cardId
,
createdAt
])
@@
map
(
"card_activities"
)
@@index([entityType, entityId])
}
model
CardTemplate
{
id
String
@
id
@
default
(
uuid
())
name
String
description
String
?
boardId
String
?
defaultColumn
String
?
priority
CardPriority
@
default
(
NONE
)
bountyPiasters
Int
@
default
(
0
)
templateData
Json
//
{
checklists
:
[...],
labels
:
[...],
description
:
"..."
}
createdById
String
createdBy
User
@
relation
(
fields
:
[
createdById
],
references
:
[
id
])
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
// ============================================
// FINANCIAL
// ============================================
recurringCards
RecurringCard
[]
model Deduction {
id String @id @default(uuid())
userId String
user User @relation("DeductionTarget", fields: [userId], references: [id])
initiatedById String?
initiatedBy User? @relation("DeductionInitiator", fields: [initiatedById], references: [id])
reviewedById String?
reviewedBy User? @relation("DeductionReviewer", fields: [reviewedById], references: [id])
cardId String?
card Card? @relation(fields: [cardId], references: [id], onDelete: SetNull)
category DeductionCategory
subCategory String
status DeductionStatus @default(DRAFT)
amountPiasters Int
appliedAmountPiasters Int?
description String
evidence Json?
violationDate DateTime?
acknowledgedAt DateTime?
contractorResponse String?
respondedAt DateTime?
reviewNotes String?
reviewedAt DateTime?
payrollMonth Int?
payrollYear Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
map
(
"card_templates"
)
@@index([userId])
@@index([status])
@@index([category])
@@index([payrollMonth, payrollYear])
@@index([createdAt])
}
model
RecurringCard
{
id
String
@
id
@
default
(
uuid
())
templateId
String
template
CardTemplate
@
relation
(
fields
:
[
templateId
],
references
:
[
id
])
boardId
String
columnId
String
pattern
RecurrencePattern
cronExpression
String
?
customDays
Json
?
//
[
1
,
3
,
5
]
for
Mon
/
Wed
/
Fri
nextRunAt
DateTime
lastRunAt
DateTime
?
isActive
Boolean
@
default
(
true
)
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
model BountyPayout {
id String @id @default(uuid())
cardId String
card Card @relation(fields: [cardId], references: [id])
userId String
user User @relation(fields: [userId], references: [id])
amountPiasters Int
splitPercentage Float @default(100)
payrollMonth Int
payrollYear Int
paidAt DateTime @default(now())
createdAt DateTime @default(now())
@@
index
([
isActive
,
nextRunAt
])
@@
map
(
"recurring_cards"
)
@@index([userId])
@@index([cardId])
@@index([payrollMonth, payrollYear])
}
model
SavedFilter
{
id
String
@
id
@
default
(
uuid
())
boardId
String
board
Board
@
relation
(
fields
:
[
boardId
],
references
:
[
id
],
onDelete
:
Cascade
)
userId
String
name
String
filters
Json
//
{
priority
:
[...],
assignees
:
[...],
labels
:
[...],
dueDate
:
...
}
isDefault
Boolean
@
default
(
false
)
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
model Adjustment {
id String @id @default(uuid())
userId String
user User @relation("AdjustmentTarget", fields: [userId], references: [id])
createdById String
createdBy User @relation("AdjustmentCreator", fields: [createdById], references: [id])
reviewedById String?
reviewedBy User? @relation("AdjustmentReviewer", fields: [reviewedById], references: [id])
type AdjustmentType
category AdjustmentCategory
amountPiasters Int
description String
status AdjustmentStatus @default(PENDING_APPROVAL)
effectiveMonth Int
effectiveYear Int
reviewNotes String?
reviewedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
index
([
boardId
,
userId
])
@@
map
(
"saved_filters"
)
}
//
============================================================
//
FINANCIAL
—
SALARY
//
============================================================
model
ContractorSalary
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
"SalaryContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
baseSalaryPiasters
Int
contractorType
ContractorType
effectiveDate
DateTime
endDate
DateTime
?
workDaysPerWeek
Int
@
default
(
5
)
hoursPerDay
Float
@
default
(
8
)
isActive
Boolean
@
default
(
true
)
notes
String
?
createdById
String
createdBy
User
@
relation
(
"SalaryCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
contractorId
])
@@
index
([
contractorId
,
isActive
])
@@
index
([
effectiveDate
])
@@
map
(
"contractor_salaries"
)
}
//
============================================================
//
FINANCIAL
—
BOUNTIES
//
============================================================
model
Bounty
{
@@index([userId])
@@index([status])
@@index([effectiveMonth, effectiveYear])
}
model Payroll {
id String @id @default(uuid())
month Int
year Int
status PayrollStatus @default(PENDING_CALCULATION)
totalGrossPiasters Int @default(0)
totalNetPiasters Int @default(0)
contractorCount Int @default(0)
calculatedAt DateTime?
submittedAt DateTime?
approvedAt DateTime?
paidAt DateTime?
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lines PayrollLine[]
@@unique([month, year])
@@index([status])
}
model PayrollLine {
id String @id @default(uuid())
payrollId String
payroll Payroll @relation(fields: [payrollId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id])
actualSalaryPiasters Int
totalBountiesPiasters Int @default(0)
totalDeductionsPiasters Int @default(0)
totalAdjustmentsPiasters Int @default(0)
netPayablePiasters Int @default(0)
breakdown Json?
createdAt DateTime @default(now())
@@index([payrollId])
@@index([userId])
}
// ============================================
// REPORTS
// ============================================
model DailyReport {
id String @id @default(uuid())
cardId
String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
])
contractorId
String
contractor
User
@
relation
(
"BountyContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
amountPiasters
Int
status
BountyStatus
@
default
(
PENDING
)
earnedAt
DateTime
?
payrollItemId
String
?
payrollItem
PayrollItem
?
@
relation
(
fields
:
[
payrollItemId
],
references
:
[
id
])
createdById
String
createdBy
User
@
relation
(
"BountyCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
month
Int
year
Int
userId String
user User @relation("ReportAuthor", fields: [userId], references: [id])
reviewedById String?
reviewedBy User? @relation("ReportReviewer", fields: [reviewedById], references: [id])
reportDate DateTime
status ReportStatus @default(DRAFT)
taskEntries Json?
blockers String?
additionalNotes String?
mood String?
totalHours Float?
submittedAt DateTime?
reviewedAt DateTime?
reviewNotes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
index
([
contractorId
])
@@
index
([
contractorId
,
month
,
year
])
@@
index
([
cardId
])
amendments ReportAmendment[]
@@index([userId])
@@index([reportDate])
@@index([status])
@@
map
(
"bounties"
)
}
//
============================================================
//
FINANCIAL
—
DEDUCTIONS
//
============================================================
model ReportAmendment {
id String @id @default(uuid())
reportId String
report DailyReport @relation(fields: [reportId], references: [id], onDelete: Cascade)
reason String
content Json
status String @default("PENDING")
reviewNotes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model
DeductionPreset
{
id
String
@
id
@
default
(
uuid
())
name
String
description
String
?
amountPiasters
Int
type
DeductionType
isActive
Boolean
@
default
(
true
)
deductions
Deduction
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
@@index([reportId])
}
// ============================================
// EVALUATIONS & PERFORMANCE
// ============================================
model Evaluation {
id String @id @default(uuid())
userId String
user User @relation("EvaluationTarget", fields: [userId], references: [id])
techEvaluatorId String?
techEvaluator User? @relation("TechEvaluator", fields: [techEvaluatorId], references: [id])
profEvaluatorId String?
profEvaluator User? @relation("ProfEvaluator", fields: [profEvaluatorId], references: [id])
month Int
year Int
status EvaluationStatus @default(PENDING_TECHNICAL)
technicalScores Json?
technicalScore Float?
technicalNotes String?
professionalScores Json?
professionalScore Float?
professionalNotes String?
autoMetrics Json?
overallScore Float?
rating String?
contractorResponse String?
acknowledgedAt DateTime?
respondedAt DateTime?
compiledAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([userId, month, year])
@@index([userId])
@@index([status])
@@index([month, year])
}
model Pip {
id String @id @default(uuid())
userId String
user User @relation("PipTarget", fields: [userId], references: [id])
createdById String
createdBy User @relation("PipCreator", fields: [createdById], references: [id])
status PipStatus @default(ACTIVE)
durationDays Int
startDate DateTime @default(now())
endDate DateTime
specificIssues String
improvementTargets String
successCriteria String
consequenceOfFailure String @default("Termination of engagement.")
checkInSchedule String @default("WEEKLY")
checkIns Json?
resultNotes String?
acknowledgedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
map
(
"deduction_presets"
)
@@index([userId])
@@index([status])
}
model
Deduction
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
"DeductionContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
amountPiasters
Int
type
DeductionType
reason
String
presetId
String
?
preset
DeductionPreset
?
@
relation
(
fields
:
[
presetId
],
references
:
[
id
])
triggerCardId
String
?
triggerReportId
String
?
status
DeductionStatus
@
default
(
PENDING
)
approvedById
String
?
approvedBy
User
?
@
relation
(
"DeductionApprover"
,
fields
:
[
approvedById
],
references
:
[
id
])
approvedAt
DateTime
?
appealReason
String
?
appealedAt
DateTime
?
reversedById
String
?
reversedBy
User
?
@
relation
(
"DeductionReverser"
,
fields
:
[
reversedById
],
references
:
[
id
])
reversedAt
DateTime
?
reversalReason
String
?
month
Int
year
Int
payrollItemId
String
?
payrollItem
PayrollItem
?
@
relation
(
fields
:
[
payrollItemId
],
references
:
[
id
])
createdById
String
createdBy
User
@
relation
(
"DeductionCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
model LearningGoal {
id String @id @default(uuid())
userId String
user User @relation("GoalTarget", fields: [userId], references: [id])
createdById String
createdBy User @relation("GoalCreator", fields: [createdById], references: [id])
title String
description String
competencyAreaId String?
competencyArea CompetencyArea? @relation(fields: [competencyAreaId], references: [id])
deadline DateTime
status LearningGoalStatus @default(ACTIVE)
assessmentMethod String?
passCriteria String?
assessmentNotes String?
assessedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
index
([
contractorId
])
@@
index
([
contractorId
,
month
,
year
])
@@index([userId])
@@index([status])
@@
index
([
type
])
@@
index
([
deletedAt
])
@@
map
(
"deductions"
)
}
//
============================================================
//
FINANCIAL
—
SALARY
ADJUSTMENTS
//
============================================================
model CompetencyArea {
id String @id @default(uuid())
name String
description String?
position Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model
SalaryAdjustment
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
"AdjustmentContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
amountPiasters
Int
type
AdjustmentType
reason
String
status
AdjustmentStatus
@
default
(
PENDING
)
approvedById
String
?
approvedBy
User
?
@
relation
(
"AdjustmentApprover"
,
fields
:
[
approvedById
],
references
:
[
id
])
approvedAt
DateTime
?
month
Int
year
Int
payrollItemId
String
?
payrollItem
PayrollItem
?
@
relation
(
fields
:
[
payrollItemId
],
references
:
[
id
])
createdById
String
createdBy
User
@
relation
(
"AdjustmentCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
learningGoals LearningGoal[]
}
@@
index
([
contractorId
])
@@
index
([
contractorId
,
month
,
year
])
@@
index
([
status
])
@@
map
(
"salary_adjustments"
)
}
//
============================================================
//
FINANCIAL
—
PAYROLL
//
============================================================
model
PayrollPeriod
{
id
String
@
id
@
default
(
uuid
())
month
Int
year
Int
status
PayrollStatus
@
default
(
DRAFT
)
totalGrossPiasters
Int
@
default
(
0
)
totalDeductionsPiasters
Int
@
default
(
0
)
totalBountiesPiasters
Int
@
default
(
0
)
totalAdjustmentsPiasters
Int
@
default
(
0
)
totalNetPiasters
Int
@
default
(
0
)
contractorCount
Int
@
default
(
0
)
generatedById
String
?
generatedBy
User
?
@
relation
(
"PayrollGenerator"
,
fields
:
[
generatedById
],
references
:
[
id
])
approvedById
String
?
approvedBy
User
?
@
relation
(
"PayrollApprover"
,
fields
:
[
approvedById
],
references
:
[
id
])
approvedAt
DateTime
?
paidAt
DateTime
?
notes
String
?
items
PayrollItem
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
// ============================================
// COMMUNICATION
// ============================================
@@
unique
([
month
,
year
])
@@
index
([
status
])
@@
map
(
"payroll_periods"
)
}
model
PayrollItem
{
id
String
@
id
@
default
(
uuid
())
payrollPeriodId
String
payrollPeriod
PayrollPeriod
@
relation
(
fields
:
[
payrollPeriodId
],
references
:
[
id
],
onDelete
:
Cascade
)
contractorId
String
contractor
User
@
relation
(
fields
:
[
contractorId
],
references
:
[
id
])
baseSalaryPiasters
Int
totalBountiesPiasters
Int
@
default
(
0
)
totalAdjustmentsPiasters
Int
@
default
(
0
)
totalDeductionsPiasters
Int
@
default
(
0
)
netSalaryPiasters
Int
breakdown
Json
?
//
detailed
breakdown
bounties
Bounty
[]
deductions
Deduction
[]
adjustments
SalaryAdjustment
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
unique
([
payrollPeriodId
,
contractorId
])
@@
index
([
contractorId
])
@@
map
(
"payroll_items"
)
}
//
============================================================
//
COMMUNICATION
—
CONVERSATIONS
&
MESSAGES
//
============================================================
model Notification {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
type NotificationType @default(INFORMATIONAL)
title String
message String?
link String?
isRead Boolean @default(false)
isAcknowledged Boolean @default(false)
acknowledgedAt DateTime?
createdAt DateTime @default(now())
@@index([userId])
@@index([type])
@@index([isRead])
@@index([createdAt])
}
model Conversation {
id
String
@
id
@
default
(
uuid
())
type
ConversationType
name
String
?
avatar
String
?
id String @id @default(uuid())
name String?
type ConversationType @default(DIRECT)
lastMessageAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
participants ConversationParticipant[]
messages Message[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
type
])
@@index([lastMessageAt])
@@
map
(
"conversations"
)
}
model ConversationParticipant {
...
...
@@ -1098,15 +889,12 @@ model ConversationParticipant {
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
isAdmin
Boolean
@
default
(
false
)
isMuted
Boolean
@
default
(
false
)
lastReadAt DateTime?
joinedAt
DateTime
@
default
(
now
())
leftAt
DateTime
?
createdAt DateTime @default(now())
@@unique([conversationId, userId])
@@index([conversationId])
@@index([userId])
@@
map
(
"conversation_participants"
)
}
model Message {
...
...
@@ -1115,691 +903,292 @@ model Message {
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
senderId String
sender User @relation(fields: [senderId], references: [id])
type
MessageType
@
default
(
TEXT
)
content
String
?
fileId
String
?
file
File
?
@
relation
(
fields
:
[
fileId
],
references
:
[
id
])
replyToId
String
?
replyTo
Message
?
@
relation
(
"MessageReplies"
,
fields
:
[
replyToId
],
references
:
[
id
])
replies
Message
[]
@
relation
(
"MessageReplies"
)
isEdited
Boolean
@
default
(
false
)
isPinned
Boolean
@
default
(
false
)
readBy
MessageRead
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
content String
attachments Json?
deletedAt DateTime?
createdAt DateTime @default(now())
@@index([conversationId])
@@
index
([
conversationId
,
createdAt
])
@@index([senderId])
@@
map
(
"messages"
)
}
model
MessageRead
{
id
String
@
id
@
default
(
uuid
())
messageId
String
message
Message
@
relation
(
fields
:
[
messageId
],
references
:
[
id
],
onDelete
:
Cascade
)
userId
String
readAt
DateTime
@
default
(
now
())
@@
unique
([
messageId
,
userId
])
@@
map
(
"message_reads"
)
@@index([createdAt])
}
//
============================================================
//
COMMUNICATION
—
NOTICES
&
POLICIES
//
============================================================
model Notice {
id
String
@
id
@
default
(
uuid
())
id String
@id @default(uuid())
title String
content String
priority
NotificationType
@
default
(
IMPORTANT
)
isPinned
Boolean
@
default
(
false
)
targetRoles
Role
[]
publishedAt
DateTime
?
expiresAt
DateTime
?
type NoticeType @default(GENERAL_ANNOUNCEMENT)
isBlocking Boolean @default(false)
targetRoles Json?
createdById String
createdBy
User
@
relation
(
"NoticeCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
createdBy User @relation(fields: [createdById], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
index
([
publishedAt
])
@@
index
([
deletedAt
])
@@
map
(
"notices"
)
}
model
Policy
{
id
String
@
id
@
default
(
uuid
())
title
String
content
String
version
Int
@
default
(
1
)
requiresAck
Boolean
@
default
(
true
)
targetRoles
Role
[]
effectiveDate
DateTime
createdById
String
createdBy
User
@
relation
(
"PolicyCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
acknowledgments
PolicyAcknowledgment
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
@@
index
([
effectiveDate
])
@@
index
([
deletedAt
])
@@
map
(
"policies"
)
}
acknowledgments NoticeAcknowledgment[]
model
PolicyAcknowledgment
{
id
String
@
id
@
default
(
uuid
())
policyId
String
policy
Policy
@
relation
(
fields
:
[
policyId
],
references
:
[
id
],
onDelete
:
Cascade
)
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
acknowledgedAt
DateTime
@
default
(
now
())
@@
unique
([
policyId
,
userId
])
@@
map
(
"policy_acknowledgments"
)
}
//
============================================================
//
NOTIFICATIONS
//
============================================================
model
Notification
{
id
String
@
id
@
default
(
uuid
())
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
type
NotificationType
@
default
(
PASSIVE
)
category
NotificationCategory
title
String
message
String
actionUrl
String
?
metadata
Json
?
isRead
Boolean
@
default
(
false
)
readAt
DateTime
?
acknowledgedAt
DateTime
?
expiresAt
DateTime
?
createdAt
DateTime
@
default
(
now
())
@@
index
([
userId
])
@@
index
([
userId
,
isRead
])
@@
index
([
userId
,
category
])
@@index([type])
@@index([createdAt])
@@
map
(
"notifications"
)
}
model
NotificationPreference
{
id
String
@
id
@
default
(
uuid
())
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
category
NotificationCategory
inApp
Boolean
@
default
(
true
)
sound
Boolean
@
default
(
true
)
enabled
Boolean
@
default
(
true
)
@@
unique
([
userId
,
category
])
@@
map
(
"notification_preferences"
)
}
//
============================================================
//
DAILY
REPORTS
//
============================================================
model
DailyReport
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
"ReportContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
date
DateTime
@
db
.
Date
status
ReportStatus
@
default
(
DRAFT
)
summary
String
?
submittedAt
DateTime
?
reviewedById
String
?
reviewedBy
User
?
@
relation
(
"ReportReviewer"
,
fields
:
[
reviewedById
],
references
:
[
id
])
reviewedAt
DateTime
?
reviewNotes
String
?
isLate
Boolean
@
default
(
false
)
entries
DailyReportEntry
[]
amendments
ReportAmendment
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
unique
([
contractorId
,
date
])
@@
index
([
contractorId
])
@@
index
([
contractorId
,
date
])
@@
index
([
status
])
@@
index
([
date
])
@@
map
(
"daily_reports"
)
}
model
DailyReportEntry
{
id
String
@
id
@
default
(
uuid
())
reportId
String
report
DailyReport
@
relation
(
fields
:
[
reportId
],
references
:
[
id
],
onDelete
:
Cascade
)
description
String
hoursSpent
Float
cardId
String
?
card
Card
?
@
relation
(
fields
:
[
cardId
],
references
:
[
id
])
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
reportId
])
@@
index
([
cardId
])
@@
map
(
"daily_report_entries"
)
}
model
ReportAmendment
{
id
String
@
id
@
default
(
uuid
())
reportId
String
report
DailyReport
@
relation
(
fields
:
[
reportId
],
references
:
[
id
],
onDelete
:
Cascade
)
content
String
requestedAt
DateTime
@
default
(
now
())
resolvedAt
DateTime
?
createdAt
DateTime
@
default
(
now
())
@@
index
([
reportId
])
@@
map
(
"report_amendments"
)
}
//
============================================================
//
PERFORMANCE
—
EVALUATIONS
//
============================================================
model
EvaluationTemplate
{
id
String
@
id
@
default
(
uuid
())
name
String
description
String
?
criteria
EvaluationCriteria
[]
evaluations
Evaluation
[]
isActive
Boolean
@
default
(
true
)
createdById
String
createdBy
User
@
relation
(
fields
:
[
createdById
],
references
:
[
id
])
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
@@
map
(
"evaluation_templates"
)
}
model
EvaluationCriteria
{
id
String
@
id
@
default
(
uuid
())
templateId
String
template
EvaluationTemplate
@
relation
(
fields
:
[
templateId
],
references
:
[
id
],
onDelete
:
Cascade
)
name
String
description
String
?
weight
Float
//
percentage
(
0
-
100
)
maxScore
Int
@
default
(
5
)
order
Int
scores
EvaluationScore
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
model NoticeAcknowledgment {
id String @id @default(uuid())
noticeId String
notice Notice @relation(fields: [noticeId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
@@
index
([
templateId
])
@@
map
(
"evaluation_criteria"
)
@@unique([noticeId, userId])
@@index([noticeId])
@@index([userId])
}
model
Evaluation
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
"EvaluationContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
evaluatorId
String
evaluator
User
@
relation
(
"EvaluationEvaluator"
,
fields
:
[
evaluatorId
],
references
:
[
id
])
templateId
String
?
template
EvaluationTemplate
?
@
relation
(
fields
:
[
templateId
],
references
:
[
id
])
period
String
//
"2024-Q1"
,
"2024-01"
,
etc
.
month
Int
year
Int
status
EvaluationStatus
@
default
(
DRAFT
)
overallScore
Float
?
overallComments
String
?
autoMetrics
Json
?
//
snapshot
of
computed
metrics
acknowledgedAt
DateTime
?
scores
EvaluationScore
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
contractorId
])
@@
index
([
evaluatorId
])
@@
index
([
contractorId
,
month
,
year
])
@@
index
([
status
])
@@
map
(
"evaluations"
)
}
model
EvaluationScore
{
id
String
@
id
@
default
(
uuid
())
evaluationId
String
evaluation
Evaluation
@
relation
(
fields
:
[
evaluationId
],
references
:
[
id
],
onDelete
:
Cascade
)
criteriaId
String
criteria
EvaluationCriteria
@
relation
(
fields
:
[
criteriaId
],
references
:
[
id
])
score
Float
comments
String
?
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
unique
([
evaluationId
,
criteriaId
])
@@
map
(
"evaluation_scores"
)
}
//
============================================================
//
PERFORMANCE
—
PIPs
//
============================================================
model
PIP
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
"PIPContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
managerId
String
manager
User
@
relation
(
"PIPManager"
,
fields
:
[
managerId
],
references
:
[
id
])
reason
String
status
PIPStatus
@
default
(
ACTIVE
)
startDate
DateTime
endDate
DateTime
extendedDate
DateTime
?
goals
PIPGoal
[]
checkIns
PIPCheckIn
[]
outcome
String
?
completedAt
DateTime
?
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
contractorId
])
@@
index
([
status
])
@@
index
([
managerId
])
@@
map
(
"pips"
)
}
// ============================================
// SCHEDULING & TIME
// ============================================
model
PIPGoal
{
model
Holiday
{
id String @id @default(uuid())
pipId
String
pip
PIP
@
relation
(
fields
:
[
pipId
],
references
:
[
id
],
onDelete
:
Cascade
)
title
String
description
String
?
targetDate
DateTime
?
isCompleted
Boolean
@
default
(
false
)
completedAt
DateTime
?
order
Int
name String
startDate DateTime
endDate DateTime
isRecurring Boolean @default(false)
notes String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
index
([
pipId
])
@@
map
(
"pip_goals"
)
@@index([startDate])
}
model
PIPCheckIn
{
id
String
@
id
@
default
(
uuid
())
pipId
String
pip
PIP
@
relation
(
fields
:
[
pipId
],
references
:
[
id
],
onDelete
:
Cascade
)
meetingId
String
?
@
unique
meeting
Meeting
?
@
relation
(
fields
:
[
meetingId
],
references
:
[
id
])
model Unavailability {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
startDate DateTime
endDate DateTime
reason UnavailabilityReason @default(PERSONAL)
notes String?
progress
String
?
date
DateTime
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
index
([
pip
Id
])
@@
map
(
"pip_check_ins"
)
@@index([
user
Id])
@@
index([startDate]
)
}
//
============================================================
//
PERFORMANCE
—
LEARNING
GOALS
&
COMPETENCIES
//
============================================================
model ScheduleChangeRequest {
id String @id @default(uuid())
userId String
user User @relation("ScheduleRequester", fields: [userId], references: [id])
reviewedById String?
reviewedBy User? @relation("ScheduleReviewer", fields: [reviewedById], references: [id])
currentSchedule Json
proposedSchedule Json
effectiveDate DateTime
reason String
status String @default("PENDING")
reviewNotes String?
reviewedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model
LearningGoal
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
fields
:
[
contractorId
],
references
:
[
id
])
title
String
description
String
?
status
LearningGoalStatus
@
default
(
NOT_STARTED
)
targetDate
DateTime
?
completedAt
DateTime
?
progress
Int
@
default
(
0
)
//
0
-
100
resources
Json
?
//
[{
title
,
url
,
type
}]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
contractorId
])
@@index([userId])
@@index([status])
@@
map
(
"learning_goals"
)
}
model
Competency
{
id
String
@
id
@
default
(
uuid
())
name
String
model
Meeting
{
id String @id @default(uuid())
title
String
description String?
category
String
?
levels
Json
//
[{
level
:
1
,
description
:
"..."
},
...]
assessments
CompetencyAssessment
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
@@
map
(
"competencies"
)
}
startTime DateTime
endTime DateTime
location String?
status MeetingStatus @default(SCHEDULED)
recurrence String?
notes Json?
createdById String
createdBy User @relation("MeetingCreator", fields: [createdById], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model
CompetencyAssessment
{
id
String
@
id
@
default
(
uuid
())
competencyId
String
competency
Competency
@
relation
(
fields
:
[
competencyId
],
references
:
[
id
])
contractorId
String
contractor
User
@
relation
(
"AssessmentContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
assessorId
String
assessor
User
@
relation
(
"AssessmentAssessor"
,
fields
:
[
assessorId
],
references
:
[
id
])
level
Int
notes
String
?
assessedAt
DateTime
@
default
(
now
())
createdAt
DateTime
@
default
(
now
())
invitees MeetingInvitee[]
@@
index
([
contractorId
])
@@
index
([
competencyId
,
contractorId
])
@@
map
(
"competency_assessments"
)
@@index([startTime])
@@index([status])
}
//
============================================================
//
TIME
&
SCHEDULING
//
============================================================
model MeetingInvitee {
id String @id @default(uuid())
meetingId String
meeting Meeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
attended Boolean @default(false)
model
WorkSchedule
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
@
unique
contractor
User
@
relation
(
fields
:
[
contractorId
],
references
:
[
id
])
workDays
Json
//
[
1
,
2
,
3
,
4
,
5
]
=
Mon
-
Fri
startTime
String
//
"09:00"
endTime
String
//
"17:00"
timezone
String
@
default
(
"Africa/Cairo"
)
effectiveDate
DateTime
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
map
(
"work_schedules"
)
}
model
UnavailabilityRequest
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
"UnavailabilityContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
type
UnavailabilityType
startDate
DateTime
endDate
DateTime
reason
String
?
status
RequestStatus
@
default
(
PENDING
)
reviewedById
String
?
reviewedBy
User
?
@
relation
(
"UnavailabilityReviewer"
,
fields
:
[
reviewedById
],
references
:
[
id
])
reviewedAt
DateTime
?
reviewNotes
String
?
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
contractorId
])
@@
index
([
status
])
@@
index
([
startDate
,
endDate
])
@@
map
(
"unavailability_requests"
)
@@unique([meetingId, userId])
@@index([meetingId])
@@index([userId])
}
model
Holiday
{
id
String
@
id
@
default
(
uuid
())
name
String
date
DateTime
@
db
.
Date
isRecurring
Boolean
@
default
(
false
)
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
// ============================================
// DOCUMENTS
// ============================================
@@
unique
([
date
])
@@
map
(
"holidays"
)
}
model Contract {
id String @id @default(uuid())
userId String
user User @relation(fields: [userId], references: [id])
contractorType String?
contractText String?
scheduleSnapshot Json?
salaryAtSigning Int?
signedAt DateTime?
signatureData Json?
startDate DateTime?
endDate DateTime?
status String @default("ACTIVE")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model
ScheduleChangeRequest
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
"ScheduleChangeContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
currentData
Json
//
snapshot
of
current
schedule
requestedData
Json
//
requested
changes
reason
String
status
RequestStatus
@
default
(
PENDING
)
reviewedById
String
?
reviewedBy
User
?
@
relation
(
"ScheduleChangeReviewer"
,
fields
:
[
reviewedById
],
references
:
[
id
])
reviewedAt
DateTime
?
reviewNotes
String
?
effectiveDate
DateTime
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
contractorId
])
@@index([userId])
@@index([status])
@@
map
(
"schedule_change_requests"
)
}
//
============================================================
//
MEETINGS
//
============================================================
model Policy {
id String @id @default(uuid())
title String
content String
version Int @default(1)
requiresAcknowledgment Boolean @default(true)
publishedAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model
Meeting
{
id
String
@
id
@
default
(
uuid
())
title
String
description
String
?
startTime
DateTime
endTime
DateTime
location
String
?
meetingUrl
String
?
status
MeetingStatus
@
default
(
SCHEDULED
)
createdById
String
createdBy
User
@
relation
(
"MeetingCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
participants
MeetingParticipant
[]
pipCheckIn
PIPCheckIn
?
notes
String
?
agenda
String
?
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
acknowledgments PolicyAcknowledgment[]
@@
index
([
startTime
])
@@
index
([
createdById
])
@@
index
([
status
])
@@
map
(
"meetings"
)
@@index([title])
}
model
MeetingParticipa
nt
{
id
String
@
id
@
default
(
uuid
())
meetingId
String
meeting
Meeting
@
relation
(
fields
:
[
meeting
Id
],
references
:
[
id
],
onDelete
:
Cascade
)
model
PolicyAcknowledgme
nt {
id String @id @default(uuid())
policyId
String
policy Policy @relation(fields: [policy
Id], references: [id], onDelete: Cascade)
userId String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
status
RequestStatus
@
default
(
PENDING
)
//
PENDING
=
invited
,
APPROVED
=
accepted
,
REJECTED
=
declined
respondedAt
DateTime
?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
@@
unique
([
meetingId
,
userId
])
@@unique([policyId, userId])
@@index([policyId])
@@index([userId])
@@
map
(
"meeting_participants"
)
}
//
============================================
================
//
CONTRACTS
&
OFFBOARDING
//
============================================
================
// ============================================
// OFFBOARDING
// ============================================
model
Contract
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
fields
:
[
contractorId
],
references
:
[
id
])
title
String
content
String
?
fileId
String
?
file
File
?
@
relation
(
fields
:
[
fileId
],
references
:
[
id
])
status
ContractStatus
@
default
(
DRAFT
)
startDate
DateTime
endDate
DateTime
?
salaryPiasters
Int
?
contractorType
ContractorType
?
terms
Json
?
signedAt
DateTime
?
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
model Termination {
id String @id @default(uuid())
userId String
type TerminationType
reason String
effectiveDate DateTime
noticeDate DateTime @default(now())
finalSettlement Json?
checklistItems Json?
status String @default("INITIATED")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
index
([
contractorId
])
@@
index
([
status
])
@@
map
(
"contracts"
)
}
model
OffboardingProcess
{
id
String
@
id
@
default
(
uuid
())
contractorId
String
contractor
User
@
relation
(
"OffboardingContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
initiatedById
String
initiatedBy
User
@
relation
(
"OffboardingInitiator"
,
fields
:
[
initiatedById
],
references
:
[
id
])
status
OffboardingStatus
@
default
(
PENDING
)
reason
String
?
effectiveDate
DateTime
items
OffboardingItem
[]
notes
String
?
completedAt
DateTime
?
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
contractorId
])
@@index([userId])
@@index([status])
@@
map
(
"offboarding_processes"
)
}
model
OffboardingItem
{
id
String
@
id
@
default
(
uuid
())
offboardingId
String
offboarding
OffboardingProcess
@
relation
(
fields
:
[
offboardingId
],
references
:
[
id
],
onDelete
:
Cascade
)
title
String
description
String
?
isCompleted
Boolean
@
default
(
false
)
completedAt
DateTime
?
order
Int
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
// ============================================
// ONBOARDING
// ============================================
model Invite {
id String @id @default(uuid())
code String @unique
contractorType ContractorType
status InviteStatus @default(ACTIVE)
welcomeNote String?
expiresAt DateTime
usedAt DateTime?
usedById String?
createdById String
createdBy User @relation(fields: [createdById], references: [id])
createdAt DateTime @default(now())
@@
index
([
offboardingId
])
@@
map
(
"offboarding_items"
)
@@index([
code
])
@@
index([status]
)
}
//
============================================
================
//
API
KEYS
&
WEBHOOK
S
//
============================================
================
// ============================================
// API
& INTEGRATION
S
// ============================================
model ApiKey {
id
String
@
id
@
default
(
uuid
())
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
])
id String @id @default(uuid())
name String
keyHash
String
@
unique
keyPrefix
String
//
first
8
chars
for
identification
permissions
Json
//
[
"cards:read"
,
"cards:write"
,
...]
expiresAt
DateTime
?
keyHash String @unique
keyPrefix String
scope ApiKeyScope @default(READ_ONLY)
description String?
isActive Boolean @default(true)
lastUsedAt DateTime?
isActive
Boolean
@
default
(
true
)
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
expiresAt DateTime?
createdAt DateTime
@default(now())
updatedAt DateTime
@updatedAt
@@index([keyHash])
@@
index
([
userId
])
@@
map
(
"api_keys"
)
@@index([isActive])
}
model Webhook {
id
String
@
id
@
default
(
uuid
())
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
])
name
String
url
String
secret
String
events
String
[]
//
[
"card.created"
,
"card.moved"
,
...]
status
WebhookStatus
@
default
(
ACTIVE
)
failCount
Int
@
default
(
0
)
deliveries
WebhookDelivery
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
id String @id @default(uuid())
url String
secret String?
events Json
isActive Boolean @default(true)
lastTriggeredAt DateTime?
failureCount Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
index
([
userId
])
@@
index
([
status
])
@@
map
(
"webhooks"
)
@@index([isActive])
}
model
WebhookDelivery
{
id
String
@
id
@
default
(
uuid
())
webhookId
String
webhook
Webhook
@
relation
(
fields
:
[
webhookId
],
references
:
[
id
],
onDelete
:
Cascade
)
event
String
payload
Json
responseCode
Int
?
responseBody
String
?
success
Boolean
attemptCount
Int
@
default
(
1
)
deliveredAt
DateTime
@
default
(
now
())
@@
index
([
webhookId
])
@@
index
([
webhookId
,
deliveredAt
])
@@
map
(
"webhook_deliveries"
)
}
//
============================================================
//
FILES
//
============================================================
model
File
{
id
String
@
id
@
default
(
uuid
())
originalName
String
storagePath
String
storageKey
String
@
unique
mimeType
String
sizeBytes
Int
uploadedById
String
uploadedBy
User
@
relation
(
fields
:
[
uploadedById
],
references
:
[
id
])
createdAt
DateTime
@
default
(
now
())
//
Reverse
relations
cardAttachments
CardAttachment
[]
messages
Message
[]
contracts
Contract
[]
@@
index
([
uploadedById
])
@@
index
([
storageKey
])
@@
map
(
"files"
)
}
//
============================================================
//
PRIVATE
NOTES
(
Admin
-
only
,
invisible
to
contractor
)
//
============================================================
model
PrivateNote
{
id
String
@
id
@
default
(
uuid
())
subjectId
String
subject
User
@
relation
(
"NoteSubject"
,
fields
:
[
subjectId
],
references
:
[
id
])
authorId
String
author
User
@
relation
(
"NoteAuthor"
,
fields
:
[
authorId
],
references
:
[
id
])
content
String
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
model SavedFilter {
id String @id @default(uuid())
boardId String
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
userId String
name String
filters Json
createdAt DateTime @default(now())
@@
index
([
subjectId
])
@@
index
([
authorId
])
@@
map
(
"private_notes"
)
@@index([boardId, userId])
}
//
============================================================
//
ACTIVITY
FEED
//
============================================================
model
ActivityFeedItem
{
id
String
@
id
@
default
(
uuid
())
actorId
String
actor
User
@
relation
(
"ActivityActor"
,
fields
:
[
actorId
],
references
:
[
id
])
action
String
//
"completed_card"
,
"earned_bounty"
,
"submitted_report"
,
etc
.
entityType
String
entityId
String
metadata
Json
?
//
{
cardTitle
:
"..."
,
boardName
:
"..."
,
amount
:
5000
}
visibility
String
@
default
(
"org"
)
//
"org"
,
"team"
,
"admin"
createdAt
DateTime
@
default
(
now
())
model RecurringCardDefinition {
id String @id @default(uuid())
boardId String
title String
description String?
labels Json?
priority CardPriority @default(NONE)
assigneeIds Json?
checklists Json?
estimatedHours Float?
recurrenceType RecurrenceType
recurrenceConfig Json?
isActive Boolean @default(true)
nextRunAt DateTime?
lastRunAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
index
([
actorId
])
@@
index
([
entityType
,
entityId
])
@@
index
([
createdAt
])
@@
index
([
visibility
,
createdAt
])
@@
map
(
"activity_feed_items"
)
@@index([boardId])
@@index([isActive])
}
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment