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
//
============================================================
//
This
is
your
main
Prisma
schema
file
.
//
AL
-
ARCADE
HR
PLATFORM
v3
.0
—
"THE GRIND"
//
Since
we
're using multi-file schemas, ensure your package.json
//
Complete
Prisma
Schema
—
ALL
modules
,
ALL
phases
// has the correct prisma configuration.
//
============================================================
generator client {
generator client {
provider = "prisma-client-js"
provider = "prisma-client-js"
previewFeatures
=
[
"
fullTextSearch"
,
"fullTextIndex
"
]
previewFeatures = ["
multiSchema", "prismaSchemaFolder
"]
}
}
datasource db {
datasource db {
...
@@ -13,51 +12,34 @@ datasource db {
...
@@ -13,51 +12,34 @@ datasource db {
url = env("DATABASE_URL")
url = env("DATABASE_URL")
}
}
//
============================================
================
// ============================================
// ENUMS
// ENUMS
//
============================================
================
// ============================================
enum Role {
enum Role {
SUPER_ADMIN
SUPER_ADMIN
ADMIN
ADMIN
TEAM_LEAD
PROJECT_LEADER
CONTRACTOR
CONTRACTOR
}
}
enum ContractorType {
enum ContractorType {
FULL_TIME
FULL_TIME
PART_TIME
INTERN
PROJECT_BASED
}
}
enum
UserStatus
{
enum ContractorStatus {
INVITED
ONBOARDING
ONBOARDING
ACTIVE
ACTIVE
ON_PIP
ON_PIP
SUSPENDED
SUSPENDED
OFFBOARDING
OFFBOARDED
OFFBOARDED
}
}
enum
InviteStatus
{
enum DayType {
PENDING
IN_OFFICE
ACCEPTED
REMOTE
EXPIRED
OFF
REVOKED
}
enum
BoardVisibility
{
PUBLIC
PRIVATE
TEAM
}
enum
BoardMemberRole
{
OWNER
ADMIN
MEMBER
VIEWER
}
}
enum CardPriority {
enum CardPriority {
...
@@ -68,163 +50,137 @@ enum CardPriority {
...
@@ -68,163 +50,137 @@ enum CardPriority {
NONE
NONE
}
}
enum
DeductionType
{
enum ColumnType {
MANUAL
BACKLOG
AUTO_LATE_REPORT
TODO
AUTO_MISSED_REPORT
DOING
AUTO_PIP
FROZEN
PRESET
IN_REVIEW
}
DONE
CUSTOM
enum
DeductionStatus
{
PENDING
APPROVED
REJECTED
APPEALED
REVERSED
}
enum
AdjustmentType
{
ADVANCE
REIMBURSEMENT
BONUS
CORRECTION
OTHER
}
}
enum
AdjustmentStatus
{
enum DeductionCategory {
PENDING
A
APPROVED
B
REJECTED
C
D
}
}
enum
BountyStatus
{
enum DeductionStatus {
PENDING
DRAFT
EARNED
PENDING_ADMIN_REVIEW
PAID
PENDING_ACKNOWLEDGMENT
PENDING_RESPONSE
UPHELD
REDUCED
DISMISSED
AUTO_APPLIED
CANCELLED
CANCELLED
}
}
enum
Payroll
Status
{
enum
Report
Status {
DRAFT
DRAFT
CALCULATING
SUBMITTED
REVIEW
LATE
APPROVED
APPROVED
PAID
AUTO_APPROVED
CANCELLED
FLAGGED_VAGUE
}
FLAGGED_INCONSISTENT
REVISION_REQUESTED
enum
NotificationType
{
AMENDED
PASSIVE
UNREPORTED
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
}
}
enum
ReportStatus
{
enum PayrollStatus {
DRAFT
PENDING_CALCULATION
CALCULATED
UNDER_REVIEW
SUBMITTED
SUBMITTED
APPROVED
APPROVED
REJECTED
REJECTED
AMENDMENT_REQUESTED
PROCESSING
PAID
}
}
enum EvaluationStatus {
enum EvaluationStatus {
DRAFT
PENDING_TECHNICAL
IN_PROGRESS
PENDING_PROFESSIONAL
COMP
LET
ED
COMP
IL
ED
ACKNOWLEDGED
ACKNOWLEDGED
RESPONDED
}
}
enum
P
IP
Status
{
enum P
ip
Status {
ACTIVE
ACTIVE
PASSED
PASSED
FAILED
FAILED
EXTENDED
CANCELLED
CANCELLED
}
}
enum LearningGoalStatus {
enum LearningGoalStatus {
NOT_STARTED
ACTIVE
IN_PROGRESS
OVERDUE
COMPLETED
PASSED
CANCELLED
FAILED
EXTENDED
}
}
enum
UnavailabilityType
{
enum NotificationType {
VACATION
BLOCKING
SICK
IMPORTANT
PERSONAL
INFORMATIONAL
EMERGENCY
}
enum NoticeType {
GENERAL_ANNOUNCEMENT
OFFICIAL_WARNING
POLICY_UPDATE
CUSTOM
}
enum AdjustmentType {
POSITIVE
NEGATIVE
}
enum AdjustmentCategory {
ADVANCE
REIMBURSEMENT
BONUS
CORRECTION
LOAN
OTHER
OTHER
}
}
enum
Reques
tStatus
{
enum
Adjustmen
tStatus {
PENDING
PENDING
_APPROVAL
APPROVED
APPROVED
REJECTED
REJECTED
CANCELLED
}
enum
MeetingStatus
{
SCHEDULED
IN_PROGRESS
COMPLETED
CANCELLED
}
}
enum
ContractStatus
{
enum InviteStatus {
DRAFT
ACTIVE
ACTIVE
USED
EXPIRED
EXPIRED
TERMINAT
ED
REVOK
ED
}
}
enum
OffboardingStatus
{
enum MeetingStatus {
PENDING
SCHEDULED
IN_PROGRESS
COMPLETED
COMPLETED
CANCELLED
CANCELLED
}
}
enum
WebhookStatus
{
enum UnavailabilityReason {
ACTIVE
PERSONAL
INACTIVE
MEDICAL
FAILED
RELIGIOUS
EMERGENCY
OTHER
}
}
enum
Recurrence
Pattern
{
enum Recurrence
Type
{
DAILY
DAILY
WEEKLY
WEEKLY
BIWEEKLY
BIWEEKLY
...
@@ -232,501 +188,321 @@ enum RecurrencePattern {
...
@@ -232,501 +188,321 @@ enum RecurrencePattern {
CUSTOM
CUSTOM
}
}
enum
AuditAction
{
enum LabelScope {
CREATE
ORGANIZATION
UPDATE
BOARD
DELETE
}
ARCHIVE
RESTORE
enum ApiKeyScope {
LOGIN
READ_ONLY
LOGOUT
READ_WRITE
PASSWORD_RESET
ADMIN
PASSWORD_CHANGE
}
ROLE_CHANGE
STATUS_CHANGE
enum ConversationType {
APPROVE
DIRECT
REJECT
GROUP
SUBMIT
}
MOVE
ASSIGN
enum TerminationType {
UNASSIGN
VOLUNTARY
LOCK
FOR_CAUSE
UNLOCK
MUTUAL
ACKNOWLEDGE
CONTRACT_EXPIRY
BULK_ACTION
}
EXPORT
IMPORT
// ============================================
SETTINGS_CHANGE
// CORE MODELS
GENERATE
// ============================================
SEND
}
//
============================================================
//
AUTH
&
USERS
//
============================================================
model User {
model User {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
email
String
@
unique
username String @unique
username
String
@
unique
passwordHash String
passwordHash
String
firstName String
firstName
String
lastName String
lastName
String
nameArabic String?
displayName
String
?
nationalId String? @unique
avatar
String
?
dateOfBirth DateTime?
role
Role
@
default
(
CONTRACTOR
)
phone String?
contractorType
ContractorType
?
phoneSecondary String?
status
UserStatus
@
default
(
INVITED
)
address String?
department
String
?
avatar String?
title
String
?
role Role @default(CONTRACTOR)
phone
String
?
contractorType ContractorType?
timezone
String
@
default
(
"Africa/Cairo"
)
status ContractorStatus @default(ONBOARDING)
bio
String
?
weeklySchedule Json?
dateOfBirth
DateTime
?
baseSalaryPiasters Int?
startDate
DateTime
?
actualSalaryPiasters Int?
lastLoginAt
DateTime
?
bankName String?
isOnline
Boolean
@
default
(
false
)
bankAccountNumber String?
createdAt
DateTime
@
default
(
now
())
bankAccountHolderName String?
updatedAt
DateTime
@
updatedAt
emergencyContactName String?
deletedAt
DateTime
?
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[]
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([username])
@@
index
([
role
])
@@index([status])
@@index([status])
@@index([role])
@@index([contractorType])
@@index([deletedAt])
@@index([deletedAt])
@@
index
([
department
])
@@
map
(
"users"
)
}
}
model
Session
{
model RefreshToken {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
userId
String
token String @unique
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
userId String
token
String
@
unique
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
refreshToken
String
@
unique
expiresAt DateTime
ipAddress
String
?
createdAt DateTime @default(now())
userAgent
String
?
expiresAt
DateTime
lastActiveAt
DateTime
@
default
(
now
())
createdAt
DateTime
@
default
(
now
())
@@index([userId])
@@index([userId])
@@
index
([
token
])
@@index([expiresAt])
@@index([expiresAt])
@@
map
(
"sessions"
)
}
}
model
PasswordResetToke
n
{
model
Sessio
n {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
userId
String
userId String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
token
String
@
unique
ipAddress String?
expiresAt
DateTime
userAgent String?
usedAt
DateTime
?
lastActivity DateTime @default(now())
createdAt
DateTime
@
default
(
now
())
createdAt DateTime @default(now())
@@
index
([
token
])
@@index([userId])
@@index([userId])
@@
map
(
"password_reset_tokens"
)
}
}
//
============================================================
model Setting {
//
SYSTEM
SETTINGS
//
============================================================
model
SystemSetting
{
id String @id @default(uuid())
id String @id @default(uuid())
key String @unique
key String @unique
value Json
value Json
description String?
description String?
category
String
@
default
(
"general"
)
createdAt
DateTime
@
default
(
now
())
updatedAt DateTime @updatedAt
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
@@index([key])
@@index([key])
@@
index
([
category
])
@@
map
(
"system_settings"
)
}
}
//
============================================================
model AuditTrail {
//
AUDIT
TRAIL
(
IMMUTABLE
)
id String @id @default(uuid())
//
============================================================
userId String?
action String
model
AuditLog
{
entityType String
id
String
@
id
@
default
(
uuid
())
entityId String?
userId
String
?
method String?
action
AuditAction
url String?
entityType
String
before Json?
entityId
String
?
after Json?
oldValue
Json
?
ipAddress String?
newValue
Json
?
userAgent String?
metadata
Json
?
createdAt DateTime @default(now())
ipAddress
String
?
userAgent
String
?
createdAt
DateTime
@
default
(
now
())
//
NO
updatedAt
.
NO
deletedAt
.
IMMUTABLE
.
@@index([userId])
@@index([userId])
@@
index
([
entityType
,
entityId
])
@@index([entityType])
@@index([action])
@@index([action])
@@index([createdAt])
@@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
// BOARDS & KANBAN
//
============================================
================
// ============================================
model Board {
model Board {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
name
String
name String
description
String
?
description String?
visibility
BoardVisibility
@
default
(
TEAM
)
key String @unique
createdById
String
visibility String @default("PRIVATE")
createdBy
User
@
relation
(
"BoardCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
icon String?
prefix
String
?
color String?
color
String
?
allowContractorCreation Boolean @default(true)
icon
String
?
autoArchiveDoneCardsDays Int @default(30)
isArchived
Boolean
@
default
(
false
)
isArchived Boolean @default(false)
archivedAt
DateTime
?
nextCardNumber Int @default(1)
columns
Column
[]
deletedAt DateTime?
members
BoardMember
[]
createdAt DateTime @default(now())
labels
Label
[]
updatedAt DateTime @updatedAt
cards
Card
[]
columns BoardColumn[]
members BoardMember[]
cards Card[]
labels Label[] @relation("BoardLabels")
savedFilters SavedFilter[]
savedFilters SavedFilter[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
@@
index
([
createdById
])
@@index([key])
@@
index
([
visibility
])
@@
index
([
deletedAt
])
@@index([isArchived])
@@index([isArchived])
@@
map
(
"boards"
)
@@
index([deletedAt]
)
}
}
model
Board
Member
{
model Board
Column
{
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
boardId String
boardId String
board
Board
@
relation
(
fields
:
[
boardId
],
references
:
[
id
],
onDelete
:
Cascade
)
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
userId
String
name String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
type ColumnType
role
BoardMemberRole
@
default
(
MEMBER
)
icon String?
joinedAt
DateTime
@
default
(
now
())
position Int
wipLimit Int?
@@
unique
([
boardId
,
userId
])
createdAt DateTime @default(now())
@@
index
([
userId
])
updatedAt DateTime @updatedAt
@@
map
(
"board_members"
)
}
model
BoardTemplate
{
cards Card[]
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
?
@@
map
(
"board_templates"
)
@@index([boardId])
@@index([type])
}
}
model
Column
{
model BoardMember {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
boardId
String
boardId String
board
Board
@
relation
(
fields
:
[
boardId
],
references
:
[
id
],
onDelete
:
Cascade
)
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
name
String
userId String
position
Float
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
color
String
?
role String @default("MEMBER")
wipLimit
Int
?
isDone
Boolean
@
default
(
false
)
cards
Card
[]
createdAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt
DateTime
@
updatedAt
@@unique([boardId, userId])
@@index([boardId])
@@index([boardId])
@@
index
([
boardId
,
position
])
@@index([userId])
@@
map
(
"columns"
)
}
}
model Label {
model Label {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
boardId
String
name String
board
Board
@
relation
(
fields
:
[
boardId
],
references
:
[
id
],
onDelete
:
Cascade
)
color String
name
String
textColor String @default("#FFFFFF")
color
String
scope LabelScope @default(ORGANIZATION)
cards
CardLabel
[]
boardId String?
createdAt
DateTime
@
default
(
now
())
board Board? @relation("BoardLabels", fields: [boardId], references: [id], onDelete: Cascade)
updatedAt
DateTime
@
updatedAt
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
cards CardLabel[]
@@index([scope])
@@index([boardId])
@@index([boardId])
@@
map
(
"labels"
)
}
}
//
============================================================
//
CARDS
//
============================================================
model Card {
model Card {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
title
String
description
String
?
boardId String
boardId String
board
Board
@
relation
(
fields
:
[
boardId
],
references
:
[
id
],
onDelete
:
Cascade
)
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
columnId String
columnId String
column
Column
@
relation
(
fields
:
[
columnId
],
references
:
[
id
])
column BoardColumn @relation(fields: [columnId], references: [id], onDelete: Cascade)
position
Float
cardNumber String
priority
CardPriority
@
default
(
NONE
)
title String
description String?
priority CardPriority @default(NONE)
position Float @default(0)
dueDate DateTime?
dueDate DateTime?
startDate
DateTime
?
estimatedHours Float?
estimatedHours Float?
actualHours
Float
?
bountyPiasters Int @default(0)
bountyPiasters
Int
@
default
(
0
)
bountyPaidOut Boolean @default(false)
coverImage
String
?
frozenReason String?
isLocked
Boolean
@
default
(
false
)
version Int @default(1)
lockedById
String
?
isArchived Boolean @default(false)
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
])
completedAt DateTime?
completedAt DateTime?
archivedAt
DateTime
?
firstDoingAt DateTime?
createdAt
DateTime
@
default
(
now
())
totalFrozenMs Int @default(0)
updatedAt
DateTime
@
updatedAt
createdById String
createdBy User @relation("CardCreator", fields: [createdById], references: [id])
deletedAt DateTime?
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
//
Relations
assignees CardAssignee[]
assignees
CardAssignee
[]
watchers CardWatcher[]
watchers
CardWatcher
[]
labels CardLabel[]
labels
CardLabel
[]
comments Comment[]
comments
CardComment
[]
attachments Attachment[]
checklists
Checklist
[]
checklists Checklist[]
attachments
CardAttachment
[]
bountyPayouts BountyPayout[]
activities
CardActivity
[]
deductions Deduction[]
bounties
Bounty
[]
reportEntries
DailyReportEntry
[]
@@index([boardId])
@@index([boardId])
@@index([columnId])
@@index([columnId])
@@
index
([
c
reatedById
])
@@index([c
ardNumber
])
@@
index
([
priority
])
@@index([
isArchived
])
@@index([dueDate])
@@index([dueDate])
@@index([deletedAt])
@@index([deletedAt])
@@
index
([
boardId
,
columnId
,
position
])
@@index([createdById])
@@
index
([
parentCardId
])
@@
map
(
"cards"
)
}
}
model CardAssignee {
model CardAssignee {
id
String
@
id
@
default
(
uuid
())
id
String
@id @default(uuid())
cardId
String
cardId String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
card
Card
@relation(fields: [cardId], references: [id], onDelete: Cascade)
userId
String
userId String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
user
User
@relation(fields: [userId], references: [id], onDelete: Cascade)
assign
edAt
DateTime
@
default
(
now
())
creat
edAt DateTime @default(now())
@@unique([cardId, userId])
@@unique([cardId, userId])
@@index([cardId])
@@index([userId])
@@index([userId])
@@
map
(
"card_assignees"
)
}
}
model CardWatcher {
model CardWatcher {
id
String
@
id
@
default
(
uuid
())
id
String
@id @default(uuid())
cardId
String
cardId String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
card
Card
@relation(fields: [cardId], references: [id], onDelete: Cascade)
userId
String
userId String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
user
User
@relation(fields: [userId], references: [id], onDelete: Cascade)
addedAt
DateTime
@
default
(
now
())
createdAt
DateTime @default(now())
@@unique([cardId, userId])
@@unique([cardId, userId])
@@index([cardId])
@@index([userId])
@@index([userId])
@@
map
(
"card_watchers"
)
}
}
model CardLabel {
model CardLabel {
...
@@ -737,359 +513,374 @@ model CardLabel {
...
@@ -737,359 +513,374 @@ model CardLabel {
label Label @relation(fields: [labelId], references: [id], onDelete: Cascade)
label Label @relation(fields: [labelId], references: [id], onDelete: Cascade)
@@unique([cardId, labelId])
@@unique([cardId, labelId])
@@
map
(
"card_labels"
)
@@index([cardId])
@@index([labelId])
}
}
model
CardComment
{
// ============================================
id
String
@
id
@
default
(
uuid
())
// COMMENTS, CHECKLISTS, ATTACHMENTS
cardId
String
// ============================================
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
authorId
String
model Comment {
author
User
@
relation
(
fields
:
[
authorId
],
references
:
[
id
])
id String @id @default(uuid())
content
String
cardId String
isEdited
Boolean
@
default
(
false
)
card Card @relation(fields: [cardId], references: [id], onDelete: Cascade)
parentId
String
?
authorId String
parent
CardComment
?
@
relation
(
"CommentReplies"
,
fields
:
[
parentId
],
references
:
[
id
])
author User @relation(fields: [authorId], references: [id])
replies
CardComment
[]
@
relation
(
"CommentReplies"
)
content String
createdAt
DateTime
@
default
(
now
())
editedAt DateTime?
updatedAt
DateTime
@
updatedAt
editableUntil DateTime?
deletedAt
DateTime
?
deletedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([cardId])
@@index([cardId])
@@index([authorId])
@@index([authorId])
@@
index
([
parentId
])
@@
map
(
"card_comments"
)
}
}
model Checklist {
model Checklist {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
cardId
String
cardId String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
card Card @relation(fields: [cardId], references: [id], onDelete: Cascade)
title
String
name String
position
Float
position Int @default(0)
items
ChecklistItem
[]
createdAt DateTime @default(now())
createdAt
DateTime
@
default
(
now
())
updatedAt DateTime @updatedAt
updatedAt
DateTime
@
updatedAt
items ChecklistItem[]
@@index([cardId])
@@index([cardId])
@@
map
(
"checklists"
)
}
}
model ChecklistItem {
model ChecklistItem {
id String @id @default(uuid())
id String @id @default(uuid())
checklistId String
checklistId String
checklist Checklist @relation(fields: [checklistId], references: [id], onDelete: Cascade)
checklist Checklist @relation(fields: [checklistId], references: [id], onDelete: Cascade)
title
String
text String
isCompleted
Boolean
@
default
(
false
)
isChecked Boolean @default(false)
completedAt
DateTime
?
position Int @default(0)
assigneeId
String
?
checkedAt DateTime?
position
Float
dueDate
DateTime
?
createdAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
updatedAt DateTime @updatedAt
@@index([checklistId])
@@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
{
model Attachment {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
cardId
String
cardId String?
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
],
onDelete
:
Cascade
)
card Card? @relation(fields: [cardId], references: [id], onDelete: Cascade)
actorId
String
uploadedById String
actor
User
@
relation
(
"CardActivityActor"
,
fields
:
[
actorId
],
references
:
[
id
])
uploadedBy User @relation(fields: [uploadedById], references: [id])
action
String
//
"moved"
,
"assigned"
,
"commented"
,
"priority_changed"
,
etc
.
fileName String
details
Json
?
//
{
from
:
"To Do"
,
to
:
"In Progress"
}
fileSize Int
createdAt
DateTime
@
default
(
now
())
mimeType String
storagePath String
entityType String @default("card")
entityId String?
createdAt DateTime @default(now())
@@index([cardId])
@@index([cardId])
@@
index
([
cardId
,
createdAt
])
@@index([entityType, entityId])
@@
map
(
"card_activities"
)
}
}
model
CardTemplate
{
// ============================================
id
String
@
id
@
default
(
uuid
())
// FINANCIAL
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
?
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
{
model BountyPayout {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
templateId
String
cardId String
template
CardTemplate
@
relation
(
fields
:
[
templateId
],
references
:
[
id
])
card Card @relation(fields: [cardId], references: [id])
boardId
String
userId String
columnId
String
user User @relation(fields: [userId], references: [id])
pattern
RecurrencePattern
amountPiasters Int
cronExpression
String
?
splitPercentage Float @default(100)
customDays
Json
?
//
[
1
,
3
,
5
]
for
Mon
/
Wed
/
Fri
payrollMonth Int
nextRunAt
DateTime
payrollYear Int
lastRunAt
DateTime
?
paidAt DateTime @default(now())
isActive
Boolean
@
default
(
true
)
createdAt DateTime @default(now())
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
isActive
,
nextRunAt
])
@@index([userId])
@@
map
(
"recurring_cards"
)
@@index([cardId])
@@index([payrollMonth, payrollYear])
}
}
model
SavedFilter
{
model Adjustment {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
boardId
String
userId String
board
Board
@
relation
(
fields
:
[
boardId
],
references
:
[
id
],
onDelete
:
Cascade
)
user User @relation("AdjustmentTarget", fields: [userId], references: [id])
userId
String
createdById String
name
String
createdBy User @relation("AdjustmentCreator", fields: [createdById], references: [id])
filters
Json
//
{
priority
:
[...],
assignees
:
[...],
labels
:
[...],
dueDate
:
...
}
reviewedById String?
isDefault
Boolean
@
default
(
false
)
reviewedBy User? @relation("AdjustmentReviewer", fields: [reviewedById], references: [id])
createdAt
DateTime
@
default
(
now
())
type AdjustmentType
updatedAt
DateTime
@
updatedAt
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
])
@@index([userId])
@@
map
(
"saved_filters"
)
@@index([status])
}
@@index([effectiveMonth, effectiveYear])
}
//
============================================================
//
FINANCIAL
—
SALARY
model Payroll {
//
============================================================
id String @id @default(uuid())
month Int
model
ContractorSalary
{
year Int
id
String
@
id
@
default
(
uuid
())
status PayrollStatus @default(PENDING_CALCULATION)
contractorId
String
totalGrossPiasters Int @default(0)
contractor
User
@
relation
(
"SalaryContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
totalNetPiasters Int @default(0)
baseSalaryPiasters
Int
contractorCount Int @default(0)
contractorType
ContractorType
calculatedAt DateTime?
effectiveDate
DateTime
submittedAt DateTime?
endDate
DateTime
?
approvedAt DateTime?
workDaysPerWeek
Int
@
default
(
5
)
paidAt DateTime?
hoursPerDay
Float
@
default
(
8
)
notes String?
isActive
Boolean
@
default
(
true
)
createdAt DateTime @default(now())
notes
String
?
updatedAt DateTime @updatedAt
createdById
String
createdBy
User
@
relation
(
"SalaryCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
lines PayrollLine[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@unique([month, year])
@@index([status])
@@
index
([
contractorId
])
}
@@
index
([
contractorId
,
isActive
])
@@
index
([
effectiveDate
])
model PayrollLine {
@@
map
(
"contractor_salaries"
)
id String @id @default(uuid())
}
payrollId String
payroll Payroll @relation(fields: [payrollId], references: [id], onDelete: Cascade)
//
============================================================
userId String
//
FINANCIAL
—
BOUNTIES
user User @relation(fields: [userId], references: [id])
//
============================================================
actualSalaryPiasters Int
totalBountiesPiasters Int @default(0)
model
Bounty
{
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())
id String @id @default(uuid())
cardId
String
userId String
card
Card
@
relation
(
fields
:
[
cardId
],
references
:
[
id
])
user User @relation("ReportAuthor", fields: [userId], references: [id])
contractorId
String
reviewedById String?
contractor
User
@
relation
(
"BountyContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
reviewedBy User? @relation("ReportReviewer", fields: [reviewedById], references: [id])
amountPiasters
Int
reportDate DateTime
status
BountyStatus
@
default
(
PENDING
)
status ReportStatus @default(DRAFT)
earnedAt
DateTime
?
taskEntries Json?
payrollItemId
String
?
blockers String?
payrollItem
PayrollItem
?
@
relation
(
fields
:
[
payrollItemId
],
references
:
[
id
])
additionalNotes String?
createdById
String
mood String?
createdBy
User
@
relation
(
"BountyCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
totalHours Float?
month
Int
submittedAt DateTime?
year
Int
reviewedAt DateTime?
reviewNotes String?
createdAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
updatedAt DateTime @updatedAt
@@
index
([
contractorId
])
amendments ReportAmendment[]
@@
index
([
contractorId
,
month
,
year
])
@@
index
([
cardId
])
@@index([userId])
@@index([reportDate])
@@index([status])
@@index([status])
@@
map
(
"bounties"
)
}
}
//
============================================================
model ReportAmendment {
//
FINANCIAL
—
DEDUCTIONS
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
{
@@index([reportId])
id
String
@
id
@
default
(
uuid
())
}
name
String
description
String
?
// ============================================
amountPiasters
Int
// EVALUATIONS & PERFORMANCE
type
DeductionType
// ============================================
isActive
Boolean
@
default
(
true
)
deductions
Deduction
[]
model Evaluation {
createdAt
DateTime
@
default
(
now
())
id String @id @default(uuid())
updatedAt
DateTime
@
updatedAt
userId String
deletedAt
DateTime
?
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
{
model LearningGoal {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
contractorId
String
userId String
contractor
User
@
relation
(
"DeductionContractor"
,
fields
:
[
contractorId
],
references
:
[
id
])
user User @relation("GoalTarget", fields: [userId], references: [id])
amountPiasters
Int
createdById String
type
DeductionType
createdBy User @relation("GoalCreator", fields: [createdById], references: [id])
reason
String
title String
presetId
String
?
description String
preset
DeductionPreset
?
@
relation
(
fields
:
[
presetId
],
references
:
[
id
])
competencyAreaId String?
triggerCardId
String
?
competencyArea CompetencyArea? @relation(fields: [competencyAreaId], references: [id])
triggerReportId
String
?
deadline DateTime
status
DeductionStatus
@
default
(
PENDING
)
status LearningGoalStatus @default(ACTIVE)
approvedById
String
?
assessmentMethod String?
approvedBy
User
?
@
relation
(
"DeductionApprover"
,
fields
:
[
approvedById
],
references
:
[
id
])
passCriteria String?
approvedAt
DateTime
?
assessmentNotes String?
appealReason
String
?
assessedAt DateTime?
appealedAt
DateTime
?
createdAt DateTime @default(now())
reversedById
String
?
updatedAt DateTime @updatedAt
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
?
@@
index
([
contractorId
])
@@index([userId])
@@
index
([
contractorId
,
month
,
year
])
@@index([status])
@@index([status])
@@
index
([
type
])
@@
index
([
deletedAt
])
@@
map
(
"deductions"
)
}
}
//
============================================================
model CompetencyArea {
//
FINANCIAL
—
SALARY
ADJUSTMENTS
id String @id @default(uuid())
//
============================================================
name String
description String?
position Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model
SalaryAdjustment
{
learningGoals LearningGoal[]
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
?
@@
index
([
contractorId
])
// ============================================
@@
index
([
contractorId
,
month
,
year
])
// COMMUNICATION
@@
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
@@
unique
([
month
,
year
])
model Notification {
@@
index
([
status
])
id String @id @default(uuid())
@@
map
(
"payroll_periods"
)
userId String
}
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
type NotificationType @default(INFORMATIONAL)
model
PayrollItem
{
title String
id
String
@
id
@
default
(
uuid
())
message String?
payrollPeriodId
String
link String?
payrollPeriod
PayrollPeriod
@
relation
(
fields
:
[
payrollPeriodId
],
references
:
[
id
],
onDelete
:
Cascade
)
isRead Boolean @default(false)
contractorId
String
isAcknowledged Boolean @default(false)
contractor
User
@
relation
(
fields
:
[
contractorId
],
references
:
[
id
])
acknowledgedAt DateTime?
baseSalaryPiasters
Int
createdAt DateTime @default(now())
totalBountiesPiasters
Int
@
default
(
0
)
totalAdjustmentsPiasters
Int
@
default
(
0
)
@@index([userId])
totalDeductionsPiasters
Int
@
default
(
0
)
@@index([type])
netSalaryPiasters
Int
@@index([isRead])
breakdown
Json
?
//
detailed
breakdown
@@index([createdAt])
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 Conversation {
model Conversation {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
type
ConversationType
name String?
name
String
?
type ConversationType @default(DIRECT)
avatar
String
?
lastMessageAt DateTime?
lastMessageAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
participants ConversationParticipant[]
participants ConversationParticipant[]
messages Message[]
messages Message[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
type
])
@@index([lastMessageAt])
@@index([lastMessageAt])
@@
map
(
"conversations"
)
}
}
model ConversationParticipant {
model ConversationParticipant {
...
@@ -1098,15 +889,12 @@ model ConversationParticipant {
...
@@ -1098,15 +889,12 @@ model ConversationParticipant {
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
userId String
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
isAdmin
Boolean
@
default
(
false
)
isMuted
Boolean
@
default
(
false
)
lastReadAt DateTime?
lastReadAt DateTime?
joinedAt
DateTime
@
default
(
now
())
createdAt DateTime @default(now())
leftAt
DateTime
?
@@unique([conversationId, userId])
@@unique([conversationId, userId])
@@index([conversationId])
@@index([userId])
@@index([userId])
@@
map
(
"conversation_participants"
)
}
}
model Message {
model Message {
...
@@ -1115,691 +903,292 @@ model Message {
...
@@ -1115,691 +903,292 @@ model Message {
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
conversation Conversation @relation(fields: [conversationId], references: [id], onDelete: Cascade)
senderId String
senderId String
sender User @relation(fields: [senderId], references: [id])
sender User @relation(fields: [senderId], references: [id])
type
MessageType
@
default
(
TEXT
)
content String
content
String
?
attachments Json?
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
deletedAt DateTime?
deletedAt DateTime?
createdAt DateTime @default(now())
@@index([conversationId])
@@index([conversationId])
@@
index
([
conversationId
,
createdAt
])
@@index([senderId])
@@index([senderId])
@@
map
(
"messages"
)
@@index([createdAt])
}
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"
)
}
}
//
============================================================
//
COMMUNICATION
—
NOTICES
&
POLICIES
//
============================================================
model Notice {
model Notice {
id
String
@
id
@
default
(
uuid
())
id String
@id @default(uuid())
title String
title String
content String
content String
priority
NotificationType
@
default
(
IMPORTANT
)
type NoticeType @default(GENERAL_ANNOUNCEMENT)
isPinned
Boolean
@
default
(
false
)
isBlocking Boolean @default(false)
targetRoles
Role
[]
targetRoles Json?
publishedAt
DateTime
?
expiresAt
DateTime
?
createdById String
createdById String
createdBy
User
@
relation
(
"NoticeCreator"
,
fields
:
[
createdById
],
references
:
[
id
])
createdBy User @relation(fields: [createdById], references: [id])
createdAt
DateTime
@
default
(
now
())
createdAt DateTime @default(now())
updatedAt
DateTime
@
updatedAt
updatedAt DateTime @updatedAt
deletedAt
DateTime
?
@@
index
([
publishedAt
])
acknowledgments NoticeAcknowledgment[]
@@
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"
)
}
model
PolicyAcknowledgment
{
@@index([type])
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([createdAt])
@@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"
)
}
}
//
============================================================
model NoticeAcknowledgment {
//
PERFORMANCE
—
EVALUATIONS
id String @id @default(uuid())
//
============================================================
noticeId String
notice Notice @relation(fields: [noticeId], references: [id], onDelete: Cascade)
model
EvaluationTemplate
{
userId String
id
String
@
id
@
default
(
uuid
())
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
name
String
createdAt DateTime @default(now())
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
@@
index
([
templateId
])
@@unique([noticeId, userId])
@@
map
(
"evaluation_criteria"
)
@@index([noticeId])
@@index([userId])
}
}
model
Evaluation
{
// ============================================
id
String
@
id
@
default
(
uuid
())
// SCHEDULING & TIME
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"
)
}
model
PIPGoal
{
model
Holiday
{
id String @id @default(uuid())
id String @id @default(uuid())
pipId
String
name String
pip
PIP
@
relation
(
fields
:
[
pipId
],
references
:
[
id
],
onDelete
:
Cascade
)
startDate DateTime
title
String
endDate DateTime
description
String
?
isRecurring Boolean @default(false)
targetDate
DateTime
?
notes String?
isCompleted
Boolean
@
default
(
false
)
completedAt
DateTime
?
order
Int
createdAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
updatedAt DateTime @updatedAt
@@
index
([
pipId
])
@@index([startDate])
@@
map
(
"pip_goals"
)
}
}
model
PIPCheckIn
{
model Unavailability {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
pipId
String
userId String
pip
PIP
@
relation
(
fields
:
[
pipId
],
references
:
[
id
],
onDelete
:
Cascade
)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
meetingId
String
?
@
unique
startDate DateTime
meeting
Meeting
?
@
relation
(
fields
:
[
meetingId
],
references
:
[
id
])
endDate DateTime
reason UnavailabilityReason @default(PERSONAL)
notes String?
notes String?
progress
String
?
createdAt DateTime @default(now())
date
DateTime
updatedAt DateTime @updatedAt
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
index
([
pip
Id
])
@@index([
user
Id])
@@
map
(
"pip_check_ins"
)
@@
index([startDate]
)
}
}
//
============================================================
model ScheduleChangeRequest {
//
PERFORMANCE
—
LEARNING
GOALS
&
COMPETENCIES
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
{
@@index([userId])
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([status])
@@index([status])
@@
map
(
"learning_goals"
)
}
}
model
Competency
{
model
Meeting
{
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
name
String
title
String
description String?
description String?
category
String
?
startTime DateTime
levels
Json
//
[{
level
:
1
,
description
:
"..."
},
...]
endTime DateTime
assessments
CompetencyAssessment
[]
location String?
createdAt
DateTime
@
default
(
now
())
status MeetingStatus @default(SCHEDULED)
updatedAt
DateTime
@
updatedAt
recurrence String?
deletedAt
DateTime
?
notes Json?
createdById String
@@
map
(
"competencies"
)
createdBy User @relation("MeetingCreator", fields: [createdById], references: [id])
}
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
model
CompetencyAssessment
{
invitees MeetingInvitee[]
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
())
@@
index
([
contractorId
])
@@index([startTime])
@@
index
([
competencyId
,
contractorId
])
@@index([status])
@@
map
(
"competency_assessments"
)
}
}
//
============================================================
model MeetingInvitee {
//
TIME
&
SCHEDULING
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
{
@@unique([meetingId, userId])
id
String
@
id
@
default
(
uuid
())
@@index([meetingId])
contractorId
String
@
unique
@@index([userId])
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"
)
}
}
model
Holiday
{
// ============================================
id
String
@
id
@
default
(
uuid
())
// DOCUMENTS
name
String
// ============================================
date
DateTime
@
db
.
Date
isRecurring
Boolean
@
default
(
false
)
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
@@
unique
([
date
])
model Contract {
@@
map
(
"holidays"
)
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
{
@@index([userId])
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([status])
@@index([status])
@@
map
(
"schedule_change_requests"
)
}
}
//
============================================================
model Policy {
//
MEETINGS
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
{
acknowledgments PolicyAcknowledgment[]
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
?
@@
index
([
startTime
])
@@index([title])
@@
index
([
createdById
])
@@
index
([
status
])
@@
map
(
"meetings"
)
}
}
model
MeetingParticipa
nt
{
model
PolicyAcknowledgme
nt {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
meetingId
String
policyId
String
meeting
Meeting
@
relation
(
fields
:
[
meeting
Id
],
references
:
[
id
],
onDelete
:
Cascade
)
policy Policy @relation(fields: [policy
Id], references: [id], onDelete: Cascade)
userId String
userId String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
],
onDelete
:
Cascade
)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
status
RequestStatus
@
default
(
PENDING
)
//
PENDING
=
invited
,
APPROVED
=
accepted
,
REJECTED
=
declined
createdAt DateTime @default(now())
respondedAt
DateTime
?
@@
unique
([
meetingId
,
userId
])
@@unique([policyId, userId])
@@index([policyId])
@@index([userId])
@@index([userId])
@@
map
(
"meeting_participants"
)
}
}
//
============================================
================
// ============================================
//
CONTRACTS
&
OFFBOARDING
// OFFBOARDING
//
============================================
================
// ============================================
model
Contract
{
model Termination {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
contractorId
String
userId String
contractor
User
@
relation
(
fields
:
[
contractorId
],
references
:
[
id
])
type TerminationType
title
String
reason String
content
String
?
effectiveDate DateTime
fileId
String
?
noticeDate DateTime @default(now())
file
File
?
@
relation
(
fields
:
[
fileId
],
references
:
[
id
])
finalSettlement Json?
status
ContractStatus
@
default
(
DRAFT
)
checklistItems Json?
startDate
DateTime
status String @default("INITIATED")
endDate
DateTime
?
createdAt DateTime @default(now())
salaryPiasters
Int
?
updatedAt DateTime @updatedAt
contractorType
ContractorType
?
terms
Json
?
signedAt
DateTime
?
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
@@
index
([
contractorId
])
@@index([userId])
@@
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([status])
@@index([status])
@@
map
(
"offboarding_processes"
)
}
}
model
OffboardingItem
{
// ============================================
id
String
@
id
@
default
(
uuid
())
// ONBOARDING
offboardingId
String
// ============================================
offboarding
OffboardingProcess
@
relation
(
fields
:
[
offboardingId
],
references
:
[
id
],
onDelete
:
Cascade
)
title
String
model Invite {
description
String
?
id String @id @default(uuid())
isCompleted
Boolean
@
default
(
false
)
code String @unique
completedAt
DateTime
?
contractorType ContractorType
order
Int
status InviteStatus @default(ACTIVE)
createdAt
DateTime
@
default
(
now
())
welcomeNote String?
updatedAt
DateTime
@
updatedAt
expiresAt DateTime
usedAt DateTime?
usedById String?
createdById String
createdBy User @relation(fields: [createdById], references: [id])
createdAt DateTime @default(now())
@@
index
([
offboardingId
])
@@index([
code
])
@@
map
(
"offboarding_items"
)
@@
index([status]
)
}
}
//
============================================
================
// ============================================
//
API
KEYS
&
WEBHOOK
S
// API
& INTEGRATION
S
//
============================================
================
// ============================================
model ApiKey {
model ApiKey {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
userId
String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
])
name String
name String
keyHash
String
@
unique
keyHash String @unique
keyPrefix
String
//
first
8
chars
for
identification
keyPrefix String
permissions
Json
//
[
"cards:read"
,
"cards:write"
,
...]
scope ApiKeyScope @default(READ_ONLY)
expiresAt
DateTime
?
description String?
isActive Boolean @default(true)
lastUsedAt DateTime?
lastUsedAt DateTime?
isActive
Boolean
@
default
(
true
)
expiresAt DateTime?
createdAt
DateTime
@
default
(
now
())
createdAt DateTime
@default(now())
updatedAt
DateTime
@
updatedAt
updatedAt DateTime
@updatedAt
@@index([keyHash])
@@index([keyHash])
@@
index
([
userId
])
@@index([isActive])
@@
map
(
"api_keys"
)
}
}
model Webhook {
model Webhook {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
userId
String
url String
user
User
@
relation
(
fields
:
[
userId
],
references
:
[
id
])
secret String?
name
String
events Json
url
String
isActive Boolean @default(true)
secret
String
lastTriggeredAt DateTime?
events
String
[]
//
[
"card.created"
,
"card.moved"
,
...]
failureCount Int @default(0)
status
WebhookStatus
@
default
(
ACTIVE
)
createdAt DateTime @default(now())
failCount
Int
@
default
(
0
)
updatedAt DateTime @updatedAt
deliveries
WebhookDelivery
[]
createdAt
DateTime
@
default
(
now
())
updatedAt
DateTime
@
updatedAt
deletedAt
DateTime
?
@@
index
([
userId
])
@@index([isActive])
@@
index
([
status
])
@@
map
(
"webhooks"
)
}
}
model
WebhookDelivery
{
model SavedFilter {
id
String
@
id
@
default
(
uuid
())
id String @id @default(uuid())
webhookId
String
boardId String
webhook
Webhook
@
relation
(
fields
:
[
webhookId
],
references
:
[
id
],
onDelete
:
Cascade
)
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
event
String
userId String
payload
Json
name String
responseCode
Int
?
filters Json
responseBody
String
?
createdAt DateTime @default(now())
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
?
@@
index
([
subjectId
])
@@index([boardId, userId])
@@
index
([
authorId
])
@@
map
(
"private_notes"
)
}
}
//
============================================================
model RecurringCardDefinition {
//
ACTIVITY
FEED
id String @id @default(uuid())
//
============================================================
boardId String
title String
model
ActivityFeedItem
{
description String?
id
String
@
id
@
default
(
uuid
())
labels Json?
actorId
String
priority CardPriority @default(NONE)
actor
User
@
relation
(
"ActivityActor"
,
fields
:
[
actorId
],
references
:
[
id
])
assigneeIds Json?
action
String
//
"completed_card"
,
"earned_bounty"
,
"submitted_report"
,
etc
.
checklists Json?
entityType
String
estimatedHours Float?
entityId
String
recurrenceType RecurrenceType
metadata
Json
?
//
{
cardTitle
:
"..."
,
boardName
:
"..."
,
amount
:
5000
}
recurrenceConfig Json?
visibility
String
@
default
(
"org"
)
//
"org"
,
"team"
,
"admin"
isActive Boolean @default(true)
createdAt
DateTime
@
default
(
now
())
nextRunAt DateTime?
lastRunAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@
index
([
actorId
])
@@index([boardId])
@@
index
([
entityType
,
entityId
])
@@index([isActive])
@@
index
([
createdAt
])
@@
index
([
visibility
,
createdAt
])
@@
map
(
"activity_feed_items"
)
}
}
\ 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