package training import ( "time" "github.com/google/uuid" ) // ============================================================================ // Main Entities // ============================================================================ // TrainingModule represents a compliance training module type TrainingModule struct { ID uuid.UUID `json:"id"` TenantID uuid.UUID `json:"tenant_id"` AcademyCourseID *uuid.UUID `json:"academy_course_id,omitempty"` ModuleCode string `json:"module_code"` Title string `json:"title"` Description string `json:"description,omitempty"` RegulationArea RegulationArea `json:"regulation_area"` NIS2Relevant bool `json:"nis2_relevant"` ISOControls []string `json:"iso_controls"` // JSONB FrequencyType FrequencyType `json:"frequency_type"` ValidityDays int `json:"validity_days"` RiskWeight float64 `json:"risk_weight"` ContentType string `json:"content_type"` DurationMinutes int `json:"duration_minutes"` PassThreshold int `json:"pass_threshold"` IsActive bool `json:"is_active"` SortOrder int `json:"sort_order"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // TrainingMatrixEntry represents a role-to-module mapping in the CTM type TrainingMatrixEntry struct { ID uuid.UUID `json:"id"` TenantID uuid.UUID `json:"tenant_id"` RoleCode string `json:"role_code"` ModuleID uuid.UUID `json:"module_id"` IsMandatory bool `json:"is_mandatory"` Priority int `json:"priority"` CreatedAt time.Time `json:"created_at"` // Joined fields (optional, populated in queries) ModuleCode string `json:"module_code,omitempty"` ModuleTitle string `json:"module_title,omitempty"` } // TrainingAssignment represents a user's training assignment type TrainingAssignment struct { ID uuid.UUID `json:"id"` TenantID uuid.UUID `json:"tenant_id"` ModuleID uuid.UUID `json:"module_id"` UserID uuid.UUID `json:"user_id"` UserName string `json:"user_name"` UserEmail string `json:"user_email"` RoleCode string `json:"role_code,omitempty"` TriggerType TriggerType `json:"trigger_type"` TriggerEvent string `json:"trigger_event,omitempty"` Status AssignmentStatus `json:"status"` ProgressPercent int `json:"progress_percent"` QuizScore *float64 `json:"quiz_score,omitempty"` QuizPassed *bool `json:"quiz_passed,omitempty"` QuizAttempts int `json:"quiz_attempts"` StartedAt *time.Time `json:"started_at,omitempty"` CompletedAt *time.Time `json:"completed_at,omitempty"` Deadline time.Time `json:"deadline"` CertificateID *uuid.UUID `json:"certificate_id,omitempty"` EscalationLevel int `json:"escalation_level"` LastEscalationAt *time.Time `json:"last_escalation_at,omitempty"` EnrollmentID *uuid.UUID `json:"enrollment_id,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` // Joined fields ModuleCode string `json:"module_code,omitempty"` ModuleTitle string `json:"module_title,omitempty"` } // QuizQuestion represents a persistent quiz question for a module type QuizQuestion struct { ID uuid.UUID `json:"id"` ModuleID uuid.UUID `json:"module_id"` Question string `json:"question"` Options []string `json:"options"` // JSONB CorrectIndex int `json:"correct_index"` Explanation string `json:"explanation,omitempty"` Difficulty Difficulty `json:"difficulty"` IsActive bool `json:"is_active"` SortOrder int `json:"sort_order"` CreatedAt time.Time `json:"created_at"` } // QuizAttempt represents a single quiz attempt by a user type QuizAttempt struct { ID uuid.UUID `json:"id"` AssignmentID uuid.UUID `json:"assignment_id"` UserID uuid.UUID `json:"user_id"` Answers []QuizAnswer `json:"answers"` // JSONB Score float64 `json:"score"` Passed bool `json:"passed"` CorrectCount int `json:"correct_count"` TotalCount int `json:"total_count"` DurationSeconds *int `json:"duration_seconds,omitempty"` AttemptedAt time.Time `json:"attempted_at"` } // QuizAnswer represents a single answer within a quiz attempt type QuizAnswer struct { QuestionID uuid.UUID `json:"question_id"` SelectedIndex int `json:"selected_index"` Correct bool `json:"correct"` } // AuditLogEntry represents an entry in the training audit trail type AuditLogEntry struct { ID uuid.UUID `json:"id"` TenantID uuid.UUID `json:"tenant_id"` UserID *uuid.UUID `json:"user_id,omitempty"` Action AuditAction `json:"action"` EntityType AuditEntityType `json:"entity_type"` EntityID *uuid.UUID `json:"entity_id,omitempty"` Details map[string]interface{} `json:"details"` // JSONB IPAddress string `json:"ip_address,omitempty"` CreatedAt time.Time `json:"created_at"` } // ModuleContent represents LLM-generated or manual content for a module type ModuleContent struct { ID uuid.UUID `json:"id"` ModuleID uuid.UUID `json:"module_id"` Version int `json:"version"` ContentFormat ContentFormat `json:"content_format"` ContentBody string `json:"content_body"` Summary string `json:"summary,omitempty"` GeneratedBy string `json:"generated_by,omitempty"` LLMModel string `json:"llm_model,omitempty"` IsPublished bool `json:"is_published"` ReviewedBy *uuid.UUID `json:"reviewed_by,omitempty"` ReviewedAt *time.Time `json:"reviewed_at,omitempty"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` } // TrainingStats contains aggregated training metrics type TrainingStats struct { TotalModules int `json:"total_modules"` TotalAssignments int `json:"total_assignments"` CompletionRate float64 `json:"completion_rate"` OverdueCount int `json:"overdue_count"` PendingCount int `json:"pending_count"` InProgressCount int `json:"in_progress_count"` CompletedCount int `json:"completed_count"` AvgQuizScore float64 `json:"avg_quiz_score"` AvgCompletionDays float64 `json:"avg_completion_days"` UpcomingDeadlines int `json:"upcoming_deadlines"` // within 7 days } // ComplianceGap represents a missing or overdue training requirement type ComplianceGap struct { ModuleID uuid.UUID `json:"module_id"` ModuleCode string `json:"module_code"` ModuleTitle string `json:"module_title"` RegulationArea RegulationArea `json:"regulation_area"` RoleCode string `json:"role_code"` IsMandatory bool `json:"is_mandatory"` AssignmentID *uuid.UUID `json:"assignment_id,omitempty"` Status string `json:"status"` // "missing", "overdue", "expired" Deadline *time.Time `json:"deadline,omitempty"` } // EscalationResult represents the result of an escalation check type EscalationResult struct { AssignmentID uuid.UUID `json:"assignment_id"` UserID uuid.UUID `json:"user_id"` UserName string `json:"user_name"` UserEmail string `json:"user_email"` ModuleTitle string `json:"module_title"` PreviousLevel int `json:"previous_level"` NewLevel int `json:"new_level"` DaysOverdue int `json:"days_overdue"` EscalationLabel string `json:"escalation_label"` } // DeadlineInfo represents upcoming deadline information type DeadlineInfo struct { AssignmentID uuid.UUID `json:"assignment_id"` ModuleCode string `json:"module_code"` ModuleTitle string `json:"module_title"` UserID uuid.UUID `json:"user_id"` UserName string `json:"user_name"` Deadline time.Time `json:"deadline"` DaysLeft int `json:"days_left"` Status AssignmentStatus `json:"status"` } // ============================================================================ // Filter Types // ============================================================================ // ModuleFilters defines filters for listing modules type ModuleFilters struct { RegulationArea RegulationArea FrequencyType FrequencyType IsActive *bool NIS2Relevant *bool Search string Limit int Offset int } // AssignmentFilters defines filters for listing assignments type AssignmentFilters struct { ModuleID *uuid.UUID UserID *uuid.UUID RoleCode string Status AssignmentStatus Overdue *bool Limit int Offset int } // AuditLogFilters defines filters for listing audit log entries type AuditLogFilters struct { UserID *uuid.UUID Action AuditAction EntityType AuditEntityType Limit int Offset int } // CanonicalControlSummary is a lightweight view on canonical_controls for the training pipeline type CanonicalControlSummary struct { ControlID string `json:"control_id"` Title string `json:"title"` Objective string `json:"objective"` Rationale string `json:"rationale"` Requirements []string `json:"requirements"` Severity string `json:"severity"` Category string `json:"category"` TargetAudience string `json:"target_audience"` Tags []string `json:"tags"` } // CanonicalControlMeta provides aggregated metadata about canonical controls type CanonicalControlMeta struct { Domains []DomainCount `json:"domains"` Categories []CategoryCount `json:"categories"` Audiences []AudienceCount `json:"audiences"` Total int `json:"total"` } // DomainCount is a domain with its control count type DomainCount struct { Domain string `json:"domain"` Count int `json:"count"` } // CategoryCount is a category with its control count type CategoryCount struct { Category string `json:"category"` Count int `json:"count"` } // AudienceCount is a target audience with its control count type AudienceCount struct { Audience string `json:"audience"` Count int `json:"count"` } // BulkResult holds the result of a bulk generation operation type BulkResult struct { Generated int `json:"generated"` Skipped int `json:"skipped"` Errors []string `json:"errors"` }