Files
Benell/prisma/schema.prisma
2026-03-31 13:21:48 +00:00

1636 lines
54 KiB
Plaintext

generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum RoleKey {
owner
leader
employee
}
enum DepartmentKey {
marketing
administracion
capital_humano
operaciones
proyectos
}
enum MarketingMeetingStatus {
requested
scheduled
completed
cancelled
}
enum MarketingInitiativeType {
evento
campania
cambio
implementacion
otro
}
enum MarketingInitiativeStatus {
planning
in_progress
completion
results
evaluation
}
enum MarketingTaskStatus {
todo
in_progress
blocked
done
}
enum MarketingPublicOpinion {
positive
mixed
negative
}
enum MarketingMilestoneStatus {
pending
in_progress
completed
}
enum MeetingResponseStatus {
pending
accepted
declined
}
enum ProjectCalendarVisibility {
personal
team
}
enum ProjectCaptureEvidenceKind {
photo
document
link
}
enum CaptureMode {
manual
auto
hybrid
}
enum CaptureAutomationRunStatus {
queued
running
success
failed
}
enum WeeklyKpiStatus {
on_track
watch
risk
no_score
}
enum MarketingSyncRunStatus {
queued
running
success
failed
}
enum EmploymentStatus {
active
leave
terminated
}
enum EmployeeLifecycleEventType {
hire
transfer
leave
termination
rehire
}
enum HrUpdateSeverity {
info
warning
critical
}
enum WorkspaceConfigStatus {
draft
published
archived
}
enum HrFileRecordStatus {
missing
submitted
verified
rejected
}
enum HrVacancyStatus {
draft
open
interviewing
offered
hired
closed
cancelled
}
enum HrPayrollFrequency {
weekly
biweekly
}
enum HrPayrollLineType {
percepciones
deducciones
aportaciones
}
enum HrImportJobStatus {
queued
success
partial
failed
}
enum HrCareerContentType {
announcement
course
}
enum HrCareerAssignmentStatus {
not_started
in_progress
completed
}
enum HrComplianceBody {
imss
infonavit
fonacot
other
}
enum HrComplianceStatus {
on_time
due_soon
overdue
paid
blocked
}
enum HrCompliancePaymentStatus {
scheduled
paid
late
failed
}
enum HrAutomationTaskStatus {
queued
success
warning
failed
}
enum FactoryAssetState {
draft
active
down
retired
}
enum PmTemplateState {
draft
active
archived
}
enum PmWorkOrderState {
draft
scheduled
in_progress
completed
verified
overdue
cancelled
}
enum ReminderEventState {
queued
sent
acknowledged
escalated
failed
}
enum ApprovalState {
draft
submitted
pending_owner
approved
rejected
changes_requested
cancelled
}
enum SalesForecastState {
draft
published
superseded
}
enum ProductionPlanState {
draft
simulated
locked
approved
released
replanned
}
enum ExperienceTemplateState {
draft
published
archived
}
enum ExperienceFindingPriority {
low
medium
high
critical
}
enum ExperienceFindingStatus {
open
in_progress
resolved
closed
}
enum ExperienceScoreAggregationMode {
weighted_recent
moving_average
full_average
}
enum ExperienceTrendDirection {
up
down
flat
}
enum ExperienceSignalStatus {
green
yellow
red
}
enum ExperienceEvidenceKind {
photo
document
link
}
model User {
id String @id @default(cuid())
name String?
email String @unique
emailVerified DateTime?
image String?
passwordHash String?
status String @default("active")
department DepartmentKey?
departmentRole String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accounts Account[]
sessions Session[]
userRoles UserRole[]
invitations Invitation[] @relation("InvitedByUser")
marketingMeetingsRequested MarketingMeeting[] @relation("RequestedByUser")
marketingInitiativesOwned MarketingInitiative[] @relation("MarketingInitiativeOwner")
marketingInitiativesUpdated MarketingInitiative[] @relation("MarketingInitiativeUpdatedBy")
marketingInitiativeContributorLinks MarketingInitiativeContributor[]
marketingInitiativeEvidenceCreated MarketingInitiativeEvidence[] @relation("MarketingInitiativeEvidenceCreatedBy")
marketingTasksAssigned MarketingTask[] @relation("MarketingTaskAssignee")
marketingTaskEvidenceCreated MarketingTaskEvidence[] @relation("MarketingTaskEvidenceCreatedBy")
marketingInitiativeEdits MarketingInitiativeEdit[] @relation("MarketingInitiativeEditBy")
marketingBrandPulsesUpdated MarketingBrandPulse[] @relation("MarketingBrandPulseUpdatedBy")
marketingMilestonesCreated MarketingMilestone[] @relation("MarketingMilestoneCreatedBy")
marketingMilestoneCheckpointsCreated MarketingMilestoneCheckpoint[] @relation("MarketingMilestoneCheckpointCreatedBy")
projectMeetingParticipants MarketingMeetingParticipant[] @relation("MarketingMeetingParticipantUser")
projectCalendarEventsOwned ProjectCalendarEvent[] @relation("ProjectCalendarEventOwner")
projectCaptureEvidenceUploaded ProjectCaptureEvidence[] @relation("ProjectCaptureEvidenceUploadedBy")
kpiCaptureCatalogOwned KpiCaptureCatalog[] @relation("KpiCaptureCatalogOwner")
kpiCaptureCatalogLastCaptured KpiCaptureCatalog[] @relation("KpiCaptureCatalogLastCapturedBy")
kpiCaptureEvidenceUploaded KpiCaptureEvidence[] @relation("KpiCaptureEvidenceUploadedBy")
kpiCaptureAutomationRunsTriggered KpiCaptureAutomationRun[] @relation("KpiCaptureAutomationRunTriggeredBy")
employeeProfile EmployeeProfile?
employeeLifecycleTarget EmployeeLifecycleEvent[] @relation("EmployeeLifecycleTarget")
employeeLifecycleCreated EmployeeLifecycleEvent[] @relation("EmployeeLifecycleCreatedBy")
hrUpdatesAuthored HrUpdate[] @relation("HrUpdateAuthor")
managedLocations Location[] @relation("LocationManager")
experienceTemplatesCreated ExperienceTemplate[] @relation("ExperienceTemplateCreatedBy")
experienceEvaluationsCreated ExperienceEvaluation[] @relation("ExperienceEvaluationCreatedBy")
experienceFindingsCreated ExperienceFinding[] @relation("ExperienceFindingCreatedBy")
experienceFindingsAssigned ExperienceFinding[] @relation("ExperienceFindingAssignedTo")
experienceEvidenceUploaded ExperienceEvidence[] @relation("ExperienceEvidenceUploadedBy")
experienceScoringPoliciesCreated ExperienceScoringPolicy[] @relation("ExperienceScoringPolicyCreatedBy")
}
model Role {
id String @id @default(cuid())
key RoleKey @unique
name String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
userRoles UserRole[]
}
model UserRole {
userId String
roleId String
assignedAt DateTime @default(now())
role Role @relation(fields: [roleId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@id([userId, roleId])
}
model Invitation {
id String @id @default(cuid())
inviteeName String
email String
roleKey RoleKey
department DepartmentKey
departmentRole String
tokenHash String @unique
expiresAt DateTime
acceptedAt DateTime?
invitedById String?
createdAt DateTime @default(now())
invitedBy User? @relation("InvitedByUser", fields: [invitedById], references: [id], onDelete: SetNull)
@@index([email, expiresAt])
}
model PasswordResetToken {
id String @id @default(cuid())
email String
tokenHash String @unique
expiresAt DateTime
usedAt DateTime?
createdAt DateTime @default(now())
@@index([email, expiresAt])
}
model MarketingMeeting {
id String @id @default(cuid())
department DepartmentKey
title String
agenda String
status MarketingMeetingStatus @default(requested)
requestedById String?
requestedByName String
participantNames Json
suggestedTimes Json
scheduledFor DateTime?
completedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
requestedBy User? @relation("RequestedByUser", fields: [requestedById], references: [id], onDelete: SetNull)
commitments MarketingCommitment[]
participants MarketingMeetingParticipant[]
calendarEvent ProjectCalendarEvent? @relation("ProjectMeetingCalendarEvent")
@@index([department, status, scheduledFor])
}
model MarketingCommitment {
id String @id @default(cuid())
meetingId String
title String
description String?
ownerName String?
dueDate DateTime?
status String @default("pendiente")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
meeting MarketingMeeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
@@index([meetingId, dueDate])
}
model MarketingInitiative {
id String @id @default(cuid())
department DepartmentKey
name String
type MarketingInitiativeType
status MarketingInitiativeStatus @default(planning)
isGlobal Boolean @default(false)
ownerId String?
dueDate DateTime
completedAt DateTime?
importanceWeight Float @default(1)
leadRating1to5 Int @default(3)
trackScore Boolean @default(true)
trackTickets Boolean @default(true)
trackRevenue Boolean @default(true)
target Float @default(0)
actual Float @default(0)
ticketsTarget Int @default(0)
ticketsActual Int @default(0)
revenueTarget Float @default(0)
revenueActual Float @default(0)
plannedCost Float @default(0)
actualCost Float @default(0)
targetTicketPrice Float @default(0)
actualTicketPrice Float @default(0)
attributionChannel String?
attributionPageId String?
attributionCampaign String?
attributionStart DateTime?
attributionEnd DateTime?
autoActual Float?
autoTicketsActual Int?
autoRevenueActual Float?
autoUpdatedAt DateTime?
projectsSchemaVersion Int @default(1)
opinionPublica MarketingPublicOpinion @default(mixed)
queFunciono String @default("")
queNo String @default("")
proximoIntento String @default("")
updatedById String?
updatedByName String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
owner User? @relation("MarketingInitiativeOwner", fields: [ownerId], references: [id], onDelete: SetNull)
updatedBy User? @relation("MarketingInitiativeUpdatedBy", fields: [updatedById], references: [id], onDelete: SetNull)
contributors MarketingInitiativeContributor[]
locations MarketingInitiativeLocation[]
evidenceLinks MarketingInitiativeEvidence[]
tasks MarketingTask[]
edits MarketingInitiativeEdit[]
milestones MarketingMilestone[]
captureEvidence ProjectCaptureEvidence[]
kpiCaptureEvidence KpiCaptureEvidence[]
@@index([department, status, dueDate])
}
model MarketingInitiativeContributor {
initiativeId String
userId String
createdAt DateTime @default(now())
initiative MarketingInitiative @relation(fields: [initiativeId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@id([initiativeId, userId])
@@index([userId])
}
model MarketingInitiativeLocation {
id String @id @default(cuid())
initiativeId String
locationId String
createdAt DateTime @default(now())
initiative MarketingInitiative @relation(fields: [initiativeId], references: [id], onDelete: Cascade)
@@unique([initiativeId, locationId])
@@index([locationId])
}
model MarketingInitiativeEvidence {
id String @id @default(cuid())
initiativeId String
url String
createdById String?
createdAt DateTime @default(now())
initiative MarketingInitiative @relation(fields: [initiativeId], references: [id], onDelete: Cascade)
createdBy User? @relation("MarketingInitiativeEvidenceCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
@@index([initiativeId, createdAt])
}
model MarketingTask {
id String @id @default(cuid())
initiativeId String
title String
description String @default("")
assigneeId String?
status MarketingTaskStatus @default(todo)
dueDate DateTime
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
initiative MarketingInitiative @relation(fields: [initiativeId], references: [id], onDelete: Cascade)
assignee User? @relation("MarketingTaskAssignee", fields: [assigneeId], references: [id], onDelete: SetNull)
evidenceLinks MarketingTaskEvidence[]
captureEvidence ProjectCaptureEvidence[]
kpiCaptureEvidence KpiCaptureEvidence[]
@@index([initiativeId, status, dueDate])
@@index([assigneeId])
}
model MarketingTaskEvidence {
id String @id @default(cuid())
taskId String
url String
createdById String?
createdAt DateTime @default(now())
task MarketingTask @relation(fields: [taskId], references: [id], onDelete: Cascade)
createdBy User? @relation("MarketingTaskEvidenceCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
@@index([taskId, createdAt])
}
model MarketingInitiativeEdit {
id String @id @default(cuid())
initiativeId String
editedById String?
editedByName String
summary String
createdAt DateTime @default(now())
initiative MarketingInitiative @relation(fields: [initiativeId], references: [id], onDelete: Cascade)
editedBy User? @relation("MarketingInitiativeEditBy", fields: [editedById], references: [id], onDelete: SetNull)
@@index([initiativeId, createdAt])
}
model MarketingMilestone {
id String @id @default(cuid())
initiativeId String
title String
description String @default("")
dueDate DateTime
status MarketingMilestoneStatus @default(pending)
sortOrder Int @default(0)
createdById String?
createdByName String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
initiative MarketingInitiative @relation(fields: [initiativeId], references: [id], onDelete: Cascade)
createdBy User? @relation("MarketingMilestoneCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
checkpoints MarketingMilestoneCheckpoint[]
@@index([initiativeId, dueDate, status])
}
model MarketingMilestoneCheckpoint {
id String @id @default(cuid())
milestoneId String
note String
createdById String?
createdByName String?
createdAt DateTime @default(now())
milestone MarketingMilestone @relation(fields: [milestoneId], references: [id], onDelete: Cascade)
createdBy User? @relation("MarketingMilestoneCheckpointCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
@@index([milestoneId, createdAt])
}
model MarketingMeetingParticipant {
id String @id @default(cuid())
meetingId String
userId String?
displayName String
responseStatus MeetingResponseStatus @default(pending)
respondedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
meeting MarketingMeeting @relation(fields: [meetingId], references: [id], onDelete: Cascade)
user User? @relation("MarketingMeetingParticipantUser", fields: [userId], references: [id], onDelete: SetNull)
@@unique([meetingId, userId])
@@index([meetingId, responseStatus])
@@index([userId])
}
model ProjectCalendarEvent {
id String @id @default(cuid())
department DepartmentKey @default(proyectos)
ownerUserId String
meetingId String? @unique
title String
notes String?
startAt DateTime
endAt DateTime
visibility ProjectCalendarVisibility @default(personal)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ownerUser User @relation("ProjectCalendarEventOwner", fields: [ownerUserId], references: [id], onDelete: Cascade)
meeting MarketingMeeting? @relation("ProjectMeetingCalendarEvent", fields: [meetingId], references: [id], onDelete: SetNull)
@@index([department, startAt, endAt])
@@index([ownerUserId, startAt])
}
model ProjectCaptureEvidence {
id String @id @default(cuid())
department DepartmentKey @default(proyectos)
initiativeId String?
taskId String?
uploadedById String
kind ProjectCaptureEvidenceKind
title String
note String?
url String?
storagePath String?
mimeType String?
sizeBytes Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
initiative MarketingInitiative? @relation(fields: [initiativeId], references: [id], onDelete: SetNull)
task MarketingTask? @relation(fields: [taskId], references: [id], onDelete: SetNull)
uploadedBy User @relation("ProjectCaptureEvidenceUploadedBy", fields: [uploadedById], references: [id], onDelete: Restrict)
@@index([department, createdAt])
@@index([initiativeId, createdAt])
@@index([taskId, createdAt])
@@index([uploadedById, createdAt])
}
model KpiCaptureCatalog {
id String @id @default(cuid())
weekStart DateTime
sectionKey String
rowKey String
weeklyKpiRowId String? @unique
department DepartmentKey
captureMode CaptureMode @default(manual)
automationSource String?
ownerUserId String?
freshnessSlaHours Int @default(168)
captureNote String?
lastCapturedAt DateTime?
lastCapturedById String?
lastAutomationAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
weeklyKpiRow WeeklyKpiRow? @relation(fields: [weeklyKpiRowId], references: [id], onDelete: SetNull)
ownerUser User? @relation("KpiCaptureCatalogOwner", fields: [ownerUserId], references: [id], onDelete: SetNull)
lastCapturedBy User? @relation("KpiCaptureCatalogLastCapturedBy", fields: [lastCapturedById], references: [id], onDelete: SetNull)
evidence KpiCaptureEvidence[]
@@unique([weekStart, sectionKey, rowKey])
@@index([department, weekStart])
@@index([ownerUserId, weekStart])
}
model KpiCaptureEvidence {
id String @id @default(cuid())
department DepartmentKey
weekStart DateTime
sectionKey String
rowKey String
catalogId String?
weeklyKpiRowId String?
initiativeId String?
taskId String?
uploadedById String
kind ProjectCaptureEvidenceKind
title String
note String?
url String?
storagePath String?
mimeType String?
sizeBytes Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
catalog KpiCaptureCatalog? @relation(fields: [catalogId], references: [id], onDelete: SetNull)
weeklyKpiRow WeeklyKpiRow? @relation(fields: [weeklyKpiRowId], references: [id], onDelete: SetNull)
initiative MarketingInitiative? @relation(fields: [initiativeId], references: [id], onDelete: SetNull)
task MarketingTask? @relation(fields: [taskId], references: [id], onDelete: SetNull)
uploadedBy User @relation("KpiCaptureEvidenceUploadedBy", fields: [uploadedById], references: [id], onDelete: Restrict)
@@index([department, weekStart, createdAt])
@@index([sectionKey, rowKey, weekStart])
@@index([catalogId, createdAt])
@@index([initiativeId, createdAt])
@@index([taskId, createdAt])
@@index([uploadedById, createdAt])
}
model KpiCaptureAutomationRun {
id String @id @default(cuid())
department DepartmentKey
weekStart DateTime
source String
status CaptureAutomationRunStatus @default(queued)
rowsTouched Int @default(0)
errorMessage String?
triggeredById String?
startedAt DateTime @default(now())
completedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
triggeredBy User? @relation("KpiCaptureAutomationRunTriggeredBy", fields: [triggeredById], references: [id], onDelete: SetNull)
@@index([department, weekStart, createdAt])
@@index([status, createdAt])
}
model MarketingSocialSnapshot {
id String @id @default(cuid())
department DepartmentKey
channel String
range String
followersStart Int
followersEnd Int
engagementRate Float
reach Int
impressions Int
capturedAt DateTime
createdAt DateTime @default(now())
@@index([department, range, channel, capturedAt])
}
model MarketingBrandPulse {
id String @id @default(cuid())
department DepartmentKey
month String
rating1to5 Int
notes String @default("")
updatedById String?
updatedByName String?
updatedAt DateTime @updatedAt
createdAt DateTime @default(now())
updatedBy User? @relation("MarketingBrandPulseUpdatedBy", fields: [updatedById], references: [id], onDelete: SetNull)
@@index([department, month])
}
model MarketingMetaConnection {
id String @id @default(cuid())
department DepartmentKey @default(marketing)
accountId String
pageId String
pageName String
pageAccessToken String
tokenExpiresAt DateTime?
connectedById String?
isActive Boolean @default(true)
lastSyncedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
metrics MarketingSocialMetricDaily[]
syncRuns MarketingSyncRun[]
@@unique([department, pageId, isActive])
@@index([department, isActive])
}
model MarketingSocialMetricDaily {
id String @id @default(cuid())
department DepartmentKey @default(marketing)
connectionId String
channel String
metricDate DateTime
followers Int
reach Int
impressions Int
engagements Int
engagementRate Float
createdAt DateTime @default(now())
connection MarketingMetaConnection @relation(fields: [connectionId], references: [id], onDelete: Cascade)
@@unique([connectionId, channel, metricDate])
@@index([department, channel, metricDate])
}
model MarketingSyncRun {
id String @id @default(cuid())
department DepartmentKey @default(marketing)
connectionId String?
status MarketingSyncRunStatus @default(queued)
message String?
rowsIngested Int @default(0)
triggeredById String?
startedAt DateTime @default(now())
completedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
connection MarketingMetaConnection? @relation(fields: [connectionId], references: [id], onDelete: SetNull)
@@index([department, createdAt])
@@index([status, createdAt])
}
model EmployeeProfile {
id String @id @default(cuid())
userId String @unique
employeeCode String?
hireDate DateTime?
employmentType String?
managerUserId String?
locationId String?
fte Float @default(1)
employmentStatus EmploymentStatus @default(active)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([employmentStatus, hireDate])
}
model EmployeeLifecycleEvent {
id String @id @default(cuid())
userId String
eventType EmployeeLifecycleEventType
effectiveAt DateTime
reason String?
isVoluntary Boolean?
metadata Json?
createdById String?
createdAt DateTime @default(now())
user User @relation("EmployeeLifecycleTarget", fields: [userId], references: [id], onDelete: Cascade)
createdBy User? @relation("EmployeeLifecycleCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
@@index([userId, effectiveAt])
@@index([eventType, effectiveAt])
}
model HrMetricSnapshot {
id String @id @default(cuid())
department DepartmentKey?
snapshotDate DateTime
headcount Int
hires Int
exits Int
churnPct Float
medianTenureMonths Float
peopleHealthScore Float
createdAt DateTime @default(now())
@@index([snapshotDate, department])
}
model HrUpdate {
id String @id @default(cuid())
title String
body String
severity HrUpdateSeverity @default(info)
audience String @default("hc_leadership")
status String @default("draft")
publishedAt DateTime?
authorId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
author User? @relation("HrUpdateAuthor", fields: [authorId], references: [id], onDelete: SetNull)
@@index([status, publishedAt])
}
model HrWorkspaceConfigVersion {
id String @id @default(cuid())
department DepartmentKey @default(capital_humano)
version Int
status WorkspaceConfigStatus @default(draft)
name String @default("Capital Humano Workspace")
tabs Json
changeSummary String?
createdById String?
publishedById String?
publishedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([department, version])
@@index([department, status, version])
}
model HrFileRequirement {
id String @id @default(cuid())
department DepartmentKey @default(capital_humano)
key String
label String
description String?
fieldType String @default("document")
isRequired Boolean @default(true)
isActive Boolean @default(true)
sortOrder Int @default(0)
createdById String?
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
records HrEmployeeFileRecord[]
@@unique([department, key])
@@index([department, isActive, sortOrder])
}
model HrEmployeeFileRecord {
id String @id @default(cuid())
userId String
requirementId String
status HrFileRecordStatus @default(missing)
valueText String?
evidenceUrl String?
note String?
verifiedAt DateTime?
verifiedById String?
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
requirement HrFileRequirement @relation(fields: [requirementId], references: [id], onDelete: Cascade)
@@unique([userId, requirementId])
@@index([userId, status])
@@index([requirementId, status])
}
model HrIdealOrgTarget {
id String @id @default(cuid())
department DepartmentKey @default(capital_humano)
locationCode String
roleKey String
targetCount Int
isActive Boolean @default(true)
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([department, locationCode, roleKey])
@@index([department, locationCode, roleKey])
}
model HrVacancy {
id String @id @default(cuid())
department DepartmentKey @default(capital_humano)
locationCode String
roleKey String
title String
status HrVacancyStatus @default(open)
priority String @default("medium")
openedAt DateTime @default(now())
targetStartAt DateTime?
closedAt DateTime?
hiringManagerUserId String?
ownerUserId String?
notes String?
createdById String?
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([department, status, openedAt])
@@index([department, locationCode, roleKey])
}
model HrPayrollRun {
id String @id @default(cuid())
department DepartmentKey @default(capital_humano)
source String @default("contpaqi_csv")
externalRef String?
periodStart DateTime
periodEnd DateTime
frequency HrPayrollFrequency
locationCode String?
status String @default("imported")
rawHash String?
importedById String?
importedAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
lines HrPayrollLine[]
importJobs HrPayrollImportJob[]
@@index([department, periodStart, periodEnd])
@@index([department, frequency, locationCode])
@@index([rawHash])
}
model HrPayrollLine {
id String @id @default(cuid())
runId String
userId String?
personIdentifier String
lineType HrPayrollLineType
concept String
amount Float
currency String @default("MXN")
locationCode String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
run HrPayrollRun @relation(fields: [runId], references: [id], onDelete: Cascade)
@@index([runId, lineType])
@@index([userId])
@@index([locationCode, lineType])
}
model HrPayrollImportJob {
id String @id @default(cuid())
department DepartmentKey @default(capital_humano)
status HrImportJobStatus @default(queued)
sourceFileName String?
requestHash String?
message String?
rowsRead Int @default(0)
rowsImported Int @default(0)
failedRows Int @default(0)
runId String?
triggeredById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
completedAt DateTime?
run HrPayrollRun? @relation(fields: [runId], references: [id], onDelete: SetNull)
@@index([department, status, createdAt])
@@index([requestHash])
}
model HrCareerContent {
id String @id @default(cuid())
department DepartmentKey @default(capital_humano)
contentType HrCareerContentType
title String
body String
sourceDepartment DepartmentKey?
sourceRef String?
startsAt DateTime?
endsAt DateTime?
isActive Boolean @default(true)
createdById String?
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
assignments HrCareerAssignment[]
@@index([department, contentType, isActive])
@@index([sourceDepartment, createdAt])
}
model HrCareerAssignment {
id String @id @default(cuid())
contentId String
userId String
status HrCareerAssignmentStatus @default(not_started)
progressPct Float @default(0)
assignedAt DateTime @default(now())
dueAt DateTime?
completedAt DateTime?
notes String?
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
content HrCareerContent @relation(fields: [contentId], references: [id], onDelete: Cascade)
@@unique([contentId, userId])
@@index([userId, status])
}
model HrComplianceObligation {
id String @id @default(cuid())
department DepartmentKey @default(capital_humano)
body HrComplianceBody
title String
status HrComplianceStatus @default(due_soon)
locationCode String?
referencePeriod String?
dueDate DateTime?
lastPaymentAt DateTime?
lastPaymentAmount Float?
notes String?
createdById String?
updatedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
payments HrCompliancePayment[]
@@index([department, body, status, dueDate])
@@index([department, locationCode, body])
}
model HrCompliancePayment {
id String @id @default(cuid())
obligationId String
paymentDate DateTime
amount Float
status HrCompliancePaymentStatus @default(paid)
referencePeriod String?
receiptUrl String?
note String?
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
obligation HrComplianceObligation @relation(fields: [obligationId], references: [id], onDelete: Cascade)
@@index([obligationId, paymentDate])
}
model HrAutomationTask {
id String @id @default(cuid())
department DepartmentKey @default(capital_humano)
taskType String
status HrAutomationTaskStatus @default(queued)
title String
message String?
payload Json?
runAt DateTime
resolvedAt DateTime?
assignedToId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([department, status, runAt])
}
model HrExceptionQueueItem {
id String @id @default(cuid())
department DepartmentKey @default(capital_humano)
source String
errorCode String?
message String
payload Json?
status String @default("open")
retryCount Int @default(0)
lastRetriedAt DateTime?
resolvedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([department, status, createdAt])
@@index([source, status])
}
model FactoryAsset {
id String @id @default(cuid())
department DepartmentKey @default(operaciones)
assetCode String @unique
name String
category String
locationId String?
criticality Int @default(3)
state FactoryAssetState @default(active)
serviceStrategy String?
lastMaintenanceAt DateTime?
nextMaintenanceAt DateTime?
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
templates PmTemplate[]
workOrders PmWorkOrder[]
@@index([department, state])
@@index([nextMaintenanceAt, state])
}
model PmTemplate {
id String @id @default(cuid())
assetId String
title String
description String?
cadenceDays Int?
cadenceHours Int?
state PmTemplateState @default(active)
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
asset FactoryAsset @relation(fields: [assetId], references: [id], onDelete: Cascade)
workOrders PmWorkOrder[]
@@index([assetId, state])
}
model PmWorkOrder {
id String @id @default(cuid())
assetId String
templateId String?
title String
description String?
scheduledFor DateTime
dueBy DateTime
startedAt DateTime?
completedAt DateTime?
estimatedCost Float @default(0)
expectedDowntimeHours Float @default(0)
actualCost Float?
actualDowntimeHours Float?
state PmWorkOrderState @default(scheduled)
requestedById String?
approvedById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
asset FactoryAsset @relation(fields: [assetId], references: [id], onDelete: Cascade)
template PmTemplate? @relation(fields: [templateId], references: [id], onDelete: SetNull)
reminders ReminderEvent[]
approvalRequests ApprovalRequest[]
@@index([assetId, state, dueBy])
@@index([state, scheduledFor])
}
model ReminderEvent {
id String @id @default(cuid())
workOrderId String
remindAt DateTime
channel String @default("in_app")
message String?
state ReminderEventState @default(queued)
acknowledgedAt DateTime?
createdAt DateTime @default(now())
workOrder PmWorkOrder @relation(fields: [workOrderId], references: [id], onDelete: Cascade)
@@index([workOrderId, state])
@@index([remindAt, state])
}
model MaintenanceApprovalPolicy {
id String @id @default(cuid())
department DepartmentKey @default(operaciones)
costThreshold Float @default(5000)
downtimeThresholdHours Float @default(4)
ownerUserId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([department])
}
model SalesForecast {
id String @id @default(cuid())
department DepartmentKey @default(operaciones)
weekStart DateTime
weekEnd DateTime
locationId String?
sku String?
forecastUnits Float
multiplier Float @default(1.2)
state SalesForecastState @default(draft)
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([department, weekStart, state])
}
model ProductionPlan {
id String @id @default(cuid())
department DepartmentKey @default(operaciones)
weekStart DateTime
weekEnd DateTime
lineName String
plannedUnits Float
forecastUnits Float
capacityUnits Float
varianceUnits Float
state ProductionPlanState @default(draft)
createdById String?
approvedById String?
approvedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
approvalRequests ApprovalRequest[]
@@index([department, weekStart, state])
}
model ApprovalRequest {
id String @id @default(cuid())
department DepartmentKey @default(operaciones)
requestType String
workOrderId String?
productionPlanId String?
submittedById String?
approverId String?
state ApprovalState @default(submitted)
reason String?
decidedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
workOrder PmWorkOrder? @relation(fields: [workOrderId], references: [id], onDelete: SetNull)
productionPlan ProductionPlan? @relation(fields: [productionPlanId], references: [id], onDelete: SetNull)
@@index([department, state, createdAt])
}
model WeeklyKpiSnapshot {
id String @id @default(cuid())
weekStart DateTime @unique
weekEnd DateTime
source String @default("platform")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sections WeeklyKpiSection[]
@@index([weekStart, weekEnd])
}
model WeeklyKpiSection {
id String @id @default(cuid())
snapshotId String
sectionKey String
rawSectionLabel String
mappedDepartment DepartmentKey?
ownerTeamLabel String?
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
snapshot WeeklyKpiSnapshot @relation(fields: [snapshotId], references: [id], onDelete: Cascade)
rows WeeklyKpiRow[]
@@unique([snapshotId, sectionKey])
@@index([snapshotId, mappedDepartment, sortOrder])
}
model WeeklyKpiRow {
id String @id @default(cuid())
sectionId String
rowKey String
responsibilityText String
objectiveIndicatorText String?
quantityQualityText String?
complianceText String?
dueCommitmentText String?
targetValue Float?
quantityValue Float?
compliancePct Float?
dueDate DateTime?
lastCapturedAt DateTime?
lastCapturedById String?
lastAutomationAt DateTime?
captureNote String?
status WeeklyKpiStatus @default(no_score)
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
section WeeklyKpiSection @relation(fields: [sectionId], references: [id], onDelete: Cascade)
captureCatalog KpiCaptureCatalog?
captureEvidence KpiCaptureEvidence[]
@@unique([sectionId, rowKey])
@@index([sectionId, sortOrder])
@@index([status, dueDate])
}
model Location {
id String @id @default(cuid())
code String @unique
name String
city String?
managerUserId String?
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
managerUser User? @relation("LocationManager", fields: [managerUserId], references: [id], onDelete: SetNull)
evaluations ExperienceEvaluation[]
findings ExperienceFinding[]
evidence ExperienceEvidence[]
metrics ExperienceLocationMetric?
@@index([isActive, name])
}
model ExperienceTemplate {
id String @id @default(cuid())
name String
version Int
state ExperienceTemplateState @default(draft)
isDefault Boolean @default(false)
createdById String?
publishedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdBy User? @relation("ExperienceTemplateCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
categories ExperienceTemplateCategory[]
evaluations ExperienceEvaluation[]
@@unique([name, version])
@@index([state, updatedAt])
}
model ExperienceTemplateCategory {
id String @id @default(cuid())
templateId String
key String
name String
weight Float @default(1)
sortOrder Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
template ExperienceTemplate @relation(fields: [templateId], references: [id], onDelete: Cascade)
items ExperienceTemplateItem[]
responses ExperienceEvaluationResponse[]
@@unique([templateId, key])
@@index([templateId, sortOrder])
}
model ExperienceTemplateItem {
id String @id @default(cuid())
categoryId String
key String
label String
weight Float @default(1)
sortOrder Int @default(0)
allowsComment Boolean @default(true)
requiresObservation Boolean @default(false)
allowsEvidence Boolean @default(true)
isActive Boolean @default(true)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
category ExperienceTemplateCategory @relation(fields: [categoryId], references: [id], onDelete: Cascade)
responses ExperienceEvaluationResponse[]
@@unique([categoryId, key])
@@index([categoryId, sortOrder])
}
model ExperienceEvaluation {
id String @id @default(cuid())
locationId String
templateId String
createdById String?
evaluatedAt DateTime @default(now())
generalObservations String @default("")
strengths String @default("")
improvementAreas String @default("")
totalScore Float
signal ExperienceSignalStatus
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
location Location @relation(fields: [locationId], references: [id], onDelete: Restrict)
template ExperienceTemplate @relation(fields: [templateId], references: [id], onDelete: Restrict)
createdBy User? @relation("ExperienceEvaluationCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
responses ExperienceEvaluationResponse[]
findings ExperienceFinding[]
evidence ExperienceEvidence[]
metricAsLatest ExperienceLocationMetric[] @relation("ExperienceLocationMetricLastEvaluation")
@@index([locationId, evaluatedAt])
@@index([templateId, evaluatedAt])
}
model ExperienceEvaluationResponse {
id String @id @default(cuid())
evaluationId String
categoryId String
itemId String
score Int
scorePct Float
comment String?
observation String?
hasObservation Boolean @default(false)
categoryLabelSnapshot String
itemLabelSnapshot String
categoryWeightSnapshot Float
itemWeightSnapshot Float
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
evaluation ExperienceEvaluation @relation(fields: [evaluationId], references: [id], onDelete: Cascade)
category ExperienceTemplateCategory @relation(fields: [categoryId], references: [id], onDelete: Restrict)
item ExperienceTemplateItem @relation(fields: [itemId], references: [id], onDelete: Restrict)
evidence ExperienceEvidence[]
@@unique([evaluationId, itemId])
@@index([evaluationId, categoryId])
}
model ExperienceFinding {
id String @id @default(cuid())
locationId String
evaluationId String?
createdById String?
responsibleUserId String?
title String
description String @default("")
categoryKey String?
categoryLabel String?
priority ExperienceFindingPriority @default(medium)
status ExperienceFindingStatus @default(open)
dueDate DateTime?
resolvedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
location Location @relation(fields: [locationId], references: [id], onDelete: Restrict)
evaluation ExperienceEvaluation? @relation(fields: [evaluationId], references: [id], onDelete: SetNull)
createdBy User? @relation("ExperienceFindingCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
responsibleUser User? @relation("ExperienceFindingAssignedTo", fields: [responsibleUserId], references: [id], onDelete: SetNull)
evidence ExperienceEvidence[]
@@index([locationId, status, createdAt])
@@index([evaluationId])
@@index([responsibleUserId, status])
}
model ExperienceEvidence {
id String @id @default(cuid())
locationId String
evaluationId String?
findingId String?
responseId String?
uploadedById String?
kind ExperienceEvidenceKind
title String
note String?
url String?
storagePath String?
mimeType String?
sizeBytes Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
location Location @relation(fields: [locationId], references: [id], onDelete: Restrict)
evaluation ExperienceEvaluation? @relation(fields: [evaluationId], references: [id], onDelete: SetNull)
finding ExperienceFinding? @relation(fields: [findingId], references: [id], onDelete: SetNull)
response ExperienceEvaluationResponse? @relation(fields: [responseId], references: [id], onDelete: SetNull)
uploadedBy User? @relation("ExperienceEvidenceUploadedBy", fields: [uploadedById], references: [id], onDelete: SetNull)
@@index([locationId, createdAt])
@@index([evaluationId, createdAt])
@@index([findingId, createdAt])
}
model ExperienceLocationMetric {
id String @id @default(cuid())
locationId String @unique
currentScore Float @default(0)
previousScore Float @default(0)
trendDelta Float @default(0)
trendDirection ExperienceTrendDirection @default(flat)
signal ExperienceSignalStatus @default(yellow)
totalEvaluations Int @default(0)
openFindings Int @default(0)
lastEvaluationAt DateTime?
lastEvaluationId String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
location Location @relation(fields: [locationId], references: [id], onDelete: Cascade)
lastEvaluation ExperienceEvaluation? @relation("ExperienceLocationMetricLastEvaluation", fields: [lastEvaluationId], references: [id], onDelete: SetNull)
@@index([signal, currentScore])
}
model ExperienceScoringPolicy {
id String @id @default(cuid())
name String
isActive Boolean @default(true)
aggregationMode ExperienceScoreAggregationMode @default(weighted_recent)
recentWindow Int @default(3)
recentWeightsCsv String @default("0.5,0.3,0.2")
greenThreshold Float @default(85)
yellowThreshold Float @default(70)
createdById String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdBy User? @relation("ExperienceScoringPolicyCreatedBy", fields: [createdById], references: [id], onDelete: SetNull)
@@index([isActive, updatedAt])
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
@@index([userId])
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@index([userId])
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
}