portfolio/store.go (818 LOC) → store_portfolio.go, store_items.go, store_metrics.go workshop/store.go (793 LOC) → store_sessions.go, store_participants.go, store_responses.go training/models.go (757 LOC) → models_enums.go, models_core.go, models_api.go, models_blocks.go roadmap/store.go (757 LOC) → store_roadmap.go, store_items.go, store_import.go All files under 350 LOC. Zero behavior changes, same package declarations. go vet passes on all five packages. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
194 lines
8.4 KiB
Go
194 lines
8.4 KiB
Go
package training
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// ============================================================================
|
|
// Training Block Types (Controls → Schulungsmodule Pipeline)
|
|
// ============================================================================
|
|
|
|
// TrainingBlockConfig defines how canonical controls are grouped into training modules
|
|
type TrainingBlockConfig struct {
|
|
ID uuid.UUID `json:"id"`
|
|
TenantID uuid.UUID `json:"tenant_id"`
|
|
Name string `json:"name"`
|
|
Description string `json:"description,omitempty"`
|
|
DomainFilter string `json:"domain_filter,omitempty"`
|
|
CategoryFilter string `json:"category_filter,omitempty"`
|
|
SeverityFilter string `json:"severity_filter,omitempty"`
|
|
TargetAudienceFilter string `json:"target_audience_filter,omitempty"`
|
|
RegulationArea RegulationArea `json:"regulation_area"`
|
|
ModuleCodePrefix string `json:"module_code_prefix"`
|
|
FrequencyType FrequencyType `json:"frequency_type"`
|
|
DurationMinutes int `json:"duration_minutes"`
|
|
PassThreshold int `json:"pass_threshold"`
|
|
MaxControlsPerModule int `json:"max_controls_per_module"`
|
|
IsActive bool `json:"is_active"`
|
|
LastGeneratedAt *time.Time `json:"last_generated_at,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
// TrainingBlockControlLink tracks which canonical controls are linked to which module
|
|
type TrainingBlockControlLink struct {
|
|
ID uuid.UUID `json:"id"`
|
|
BlockConfigID uuid.UUID `json:"block_config_id"`
|
|
ModuleID uuid.UUID `json:"module_id"`
|
|
ControlID string `json:"control_id"`
|
|
ControlTitle string `json:"control_title"`
|
|
ControlObjective string `json:"control_objective"`
|
|
ControlRequirements []string `json:"control_requirements"`
|
|
SortOrder int `json:"sort_order"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// CreateBlockConfigRequest is the API request for creating a block config
|
|
type CreateBlockConfigRequest struct {
|
|
Name string `json:"name" binding:"required"`
|
|
Description string `json:"description,omitempty"`
|
|
DomainFilter string `json:"domain_filter,omitempty"`
|
|
CategoryFilter string `json:"category_filter,omitempty"`
|
|
SeverityFilter string `json:"severity_filter,omitempty"`
|
|
TargetAudienceFilter string `json:"target_audience_filter,omitempty"`
|
|
RegulationArea RegulationArea `json:"regulation_area" binding:"required"`
|
|
ModuleCodePrefix string `json:"module_code_prefix" binding:"required"`
|
|
FrequencyType FrequencyType `json:"frequency_type"`
|
|
DurationMinutes int `json:"duration_minutes"`
|
|
PassThreshold int `json:"pass_threshold"`
|
|
MaxControlsPerModule int `json:"max_controls_per_module"`
|
|
}
|
|
|
|
// UpdateBlockConfigRequest is the API request for updating a block config
|
|
type UpdateBlockConfigRequest struct {
|
|
Name *string `json:"name,omitempty"`
|
|
Description *string `json:"description,omitempty"`
|
|
DomainFilter *string `json:"domain_filter,omitempty"`
|
|
CategoryFilter *string `json:"category_filter,omitempty"`
|
|
SeverityFilter *string `json:"severity_filter,omitempty"`
|
|
TargetAudienceFilter *string `json:"target_audience_filter,omitempty"`
|
|
MaxControlsPerModule *int `json:"max_controls_per_module,omitempty"`
|
|
DurationMinutes *int `json:"duration_minutes,omitempty"`
|
|
PassThreshold *int `json:"pass_threshold,omitempty"`
|
|
IsActive *bool `json:"is_active,omitempty"`
|
|
}
|
|
|
|
// GenerateBlockRequest is the API request for generating modules from a block config
|
|
type GenerateBlockRequest struct {
|
|
Language string `json:"language"`
|
|
AutoMatrix bool `json:"auto_matrix"`
|
|
}
|
|
|
|
// PreviewBlockResponse shows what would be generated without writing to DB
|
|
type PreviewBlockResponse struct {
|
|
ControlCount int `json:"control_count"`
|
|
ModuleCount int `json:"module_count"`
|
|
Controls []CanonicalControlSummary `json:"controls"`
|
|
ProposedRoles []string `json:"proposed_roles"`
|
|
}
|
|
|
|
// GenerateBlockResponse shows the result of a block generation
|
|
type GenerateBlockResponse struct {
|
|
ModulesCreated int `json:"modules_created"`
|
|
ControlsLinked int `json:"controls_linked"`
|
|
MatrixEntriesCreated int `json:"matrix_entries_created"`
|
|
ContentGenerated int `json:"content_generated"`
|
|
Errors []string `json:"errors,omitempty"`
|
|
}
|
|
|
|
// ============================================================================
|
|
// Interactive Video / Checkpoint Types
|
|
// ============================================================================
|
|
|
|
// NarratorScript is an extended VideoScript with narrator persona and checkpoints
|
|
type NarratorScript struct {
|
|
Title string `json:"title"`
|
|
Intro string `json:"intro"`
|
|
Sections []NarratorSection `json:"sections"`
|
|
Outro string `json:"outro"`
|
|
TotalDurationEstimate int `json:"total_duration_estimate"`
|
|
}
|
|
|
|
// NarratorSection is one narrative section with optional checkpoint
|
|
type NarratorSection struct {
|
|
Heading string `json:"heading"`
|
|
NarratorText string `json:"narrator_text"`
|
|
BulletPoints []string `json:"bullet_points"`
|
|
Transition string `json:"transition"`
|
|
Checkpoint *CheckpointDefinition `json:"checkpoint,omitempty"`
|
|
}
|
|
|
|
// CheckpointDefinition defines a quiz checkpoint within a video
|
|
type CheckpointDefinition struct {
|
|
Title string `json:"title"`
|
|
Questions []CheckpointQuestion `json:"questions"`
|
|
}
|
|
|
|
// CheckpointQuestion is a quiz question within a checkpoint
|
|
type CheckpointQuestion struct {
|
|
Question string `json:"question"`
|
|
Options []string `json:"options"`
|
|
CorrectIndex int `json:"correct_index"`
|
|
Explanation string `json:"explanation"`
|
|
}
|
|
|
|
// Checkpoint is a DB record for a video checkpoint
|
|
type Checkpoint struct {
|
|
ID uuid.UUID `json:"id"`
|
|
ModuleID uuid.UUID `json:"module_id"`
|
|
CheckpointIndex int `json:"checkpoint_index"`
|
|
Title string `json:"title"`
|
|
TimestampSeconds float64 `json:"timestamp_seconds"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// CheckpointProgress tracks a user's progress on a checkpoint
|
|
type CheckpointProgress struct {
|
|
ID uuid.UUID `json:"id"`
|
|
AssignmentID uuid.UUID `json:"assignment_id"`
|
|
CheckpointID uuid.UUID `json:"checkpoint_id"`
|
|
Passed bool `json:"passed"`
|
|
Attempts int `json:"attempts"`
|
|
LastAttemptAt *time.Time `json:"last_attempt_at,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
}
|
|
|
|
// InteractiveVideoManifest is returned to the frontend player
|
|
type InteractiveVideoManifest struct {
|
|
MediaID uuid.UUID `json:"media_id"`
|
|
StreamURL string `json:"stream_url"`
|
|
Checkpoints []CheckpointManifestEntry `json:"checkpoints"`
|
|
}
|
|
|
|
// CheckpointManifestEntry is one checkpoint in the manifest
|
|
type CheckpointManifestEntry struct {
|
|
CheckpointID uuid.UUID `json:"checkpoint_id"`
|
|
Index int `json:"index"`
|
|
Title string `json:"title"`
|
|
TimestampSeconds float64 `json:"timestamp_seconds"`
|
|
Questions []CheckpointQuestion `json:"questions"`
|
|
Progress *CheckpointProgress `json:"progress,omitempty"`
|
|
}
|
|
|
|
// SubmitCheckpointQuizRequest is the API request for submitting a checkpoint quiz
|
|
type SubmitCheckpointQuizRequest struct {
|
|
AssignmentID string `json:"assignment_id"`
|
|
Answers []int `json:"answers"`
|
|
}
|
|
|
|
// SubmitCheckpointQuizResponse is the API response for a checkpoint quiz submission
|
|
type SubmitCheckpointQuizResponse struct {
|
|
Passed bool `json:"passed"`
|
|
Score float64 `json:"score"`
|
|
Feedback []CheckpointQuizFeedback `json:"feedback"`
|
|
}
|
|
|
|
// CheckpointQuizFeedback is feedback for a single question
|
|
type CheckpointQuizFeedback struct {
|
|
Question string `json:"question"`
|
|
Correct bool `json:"correct"`
|
|
Explanation string `json:"explanation"`
|
|
}
|