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]) }