Some checks failed
ci/woodpecker/push/integration Pipeline failed
ci/woodpecker/push/main Pipeline failed
CI/CD Pipeline / Go Tests (push) Has been cancelled
CI/CD Pipeline / Python Tests (push) Has been cancelled
CI/CD Pipeline / Website Tests (push) Has been cancelled
CI/CD Pipeline / Linting (push) Has been cancelled
CI/CD Pipeline / Security Scan (push) Has been cancelled
CI/CD Pipeline / Docker Build & Push (push) Has been cancelled
CI/CD Pipeline / Integration Tests (push) Has been cancelled
CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / Deploy to Production (push) Has been cancelled
CI/CD Pipeline / CI Summary (push) Has been cancelled
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Go Security Scan (push) Has been cancelled
Security Scanning / Python Security Scan (push) Has been cancelled
Security Scanning / Node.js Security Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Security Scanning / Security Summary (push) Has been cancelled
Tests / Go Tests (push) Has been cancelled
Tests / Python Tests (push) Has been cancelled
Tests / Integration Tests (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled
Tests / All Checks Passed (push) Has been cancelled
- Academy, Whistleblower, Incidents frontend pages with API proxies and types - Vendor compliance API proxy route - Go backend handlers and models for all new SDK modules - Investor pitch-deck app with interactive slides - Blog section with DSGVO, AI Act, NIS2, glossary articles - MkDocs documentation site - CI/CD pipelines (Woodpecker, GitHub Actions), security scanning config - Planning and implementation documentation Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
227 lines
8.6 KiB
Go
227 lines
8.6 KiB
Go
package academy
|
|
|
|
import (
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
// ============================================================================
|
|
// Constants / Enums
|
|
// ============================================================================
|
|
|
|
// CourseCategory represents the category of a compliance course
|
|
type CourseCategory string
|
|
|
|
const (
|
|
CourseCategoryDSGVOBasics CourseCategory = "dsgvo_basics"
|
|
CourseCategoryITSecurity CourseCategory = "it_security"
|
|
CourseCategoryAILiteracy CourseCategory = "ai_literacy"
|
|
CourseCategoryWhistleblowerProtection CourseCategory = "whistleblower_protection"
|
|
CourseCategoryCustom CourseCategory = "custom"
|
|
)
|
|
|
|
// EnrollmentStatus represents the status of an enrollment
|
|
type EnrollmentStatus string
|
|
|
|
const (
|
|
EnrollmentStatusNotStarted EnrollmentStatus = "not_started"
|
|
EnrollmentStatusInProgress EnrollmentStatus = "in_progress"
|
|
EnrollmentStatusCompleted EnrollmentStatus = "completed"
|
|
EnrollmentStatusExpired EnrollmentStatus = "expired"
|
|
)
|
|
|
|
// LessonType represents the type of a lesson
|
|
type LessonType string
|
|
|
|
const (
|
|
LessonTypeVideo LessonType = "video"
|
|
LessonTypeText LessonType = "text"
|
|
LessonTypeQuiz LessonType = "quiz"
|
|
LessonTypeInteractive LessonType = "interactive"
|
|
)
|
|
|
|
// ============================================================================
|
|
// Main Entities
|
|
// ============================================================================
|
|
|
|
// Course represents a compliance training course
|
|
type Course struct {
|
|
ID uuid.UUID `json:"id"`
|
|
TenantID uuid.UUID `json:"tenant_id"`
|
|
Title string `json:"title"`
|
|
Description string `json:"description,omitempty"`
|
|
Category CourseCategory `json:"category"`
|
|
DurationMinutes int `json:"duration_minutes"`
|
|
RequiredForRoles []string `json:"required_for_roles"` // JSONB in DB
|
|
Lessons []Lesson `json:"lessons,omitempty"`
|
|
IsActive bool `json:"is_active"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
// Lesson represents a single lesson within a course
|
|
type Lesson struct {
|
|
ID uuid.UUID `json:"id"`
|
|
CourseID uuid.UUID `json:"course_id"`
|
|
Title string `json:"title"`
|
|
Description string `json:"description,omitempty"`
|
|
LessonType LessonType `json:"lesson_type"`
|
|
ContentURL string `json:"content_url,omitempty"`
|
|
DurationMinutes int `json:"duration_minutes"`
|
|
OrderIndex int `json:"order_index"`
|
|
QuizQuestions []QuizQuestion `json:"quiz_questions,omitempty"` // JSONB in DB
|
|
}
|
|
|
|
// QuizQuestion represents a single quiz question embedded in a lesson
|
|
type QuizQuestion struct {
|
|
Question string `json:"question"`
|
|
Options []string `json:"options"`
|
|
CorrectIndex int `json:"correct_index"`
|
|
Explanation string `json:"explanation"`
|
|
}
|
|
|
|
// Enrollment represents a user's enrollment in a course
|
|
type Enrollment struct {
|
|
ID uuid.UUID `json:"id"`
|
|
TenantID uuid.UUID `json:"tenant_id"`
|
|
CourseID uuid.UUID `json:"course_id"`
|
|
UserID uuid.UUID `json:"user_id"`
|
|
UserName string `json:"user_name"`
|
|
UserEmail string `json:"user_email"`
|
|
Status EnrollmentStatus `json:"status"`
|
|
ProgressPercent int `json:"progress_percent"`
|
|
CurrentLessonIndex int `json:"current_lesson_index"`
|
|
StartedAt *time.Time `json:"started_at,omitempty"`
|
|
CompletedAt *time.Time `json:"completed_at,omitempty"`
|
|
Deadline *time.Time `json:"deadline,omitempty"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
// Certificate represents a completion certificate for an enrollment
|
|
type Certificate struct {
|
|
ID uuid.UUID `json:"id"`
|
|
EnrollmentID uuid.UUID `json:"enrollment_id"`
|
|
UserName string `json:"user_name"`
|
|
CourseTitle string `json:"course_title"`
|
|
IssuedAt time.Time `json:"issued_at"`
|
|
ValidUntil *time.Time `json:"valid_until,omitempty"`
|
|
PDFURL string `json:"pdf_url,omitempty"`
|
|
}
|
|
|
|
// AcademyStatistics contains aggregated academy metrics
|
|
type AcademyStatistics struct {
|
|
TotalCourses int `json:"total_courses"`
|
|
TotalEnrollments int `json:"total_enrollments"`
|
|
CompletionRate float64 `json:"completion_rate"` // 0-100
|
|
OverdueCount int `json:"overdue_count"`
|
|
AvgCompletionDays float64 `json:"avg_completion_days"`
|
|
}
|
|
|
|
// ============================================================================
|
|
// Filter Types
|
|
// ============================================================================
|
|
|
|
// CourseFilters defines filters for listing courses
|
|
type CourseFilters struct {
|
|
Category CourseCategory
|
|
IsActive *bool
|
|
Search string
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// EnrollmentFilters defines filters for listing enrollments
|
|
type EnrollmentFilters struct {
|
|
CourseID *uuid.UUID
|
|
UserID *uuid.UUID
|
|
Status EnrollmentStatus
|
|
Limit int
|
|
Offset int
|
|
}
|
|
|
|
// ============================================================================
|
|
// API Request/Response Types
|
|
// ============================================================================
|
|
|
|
// CreateCourseRequest is the API request for creating a course
|
|
type CreateCourseRequest struct {
|
|
Title string `json:"title" binding:"required"`
|
|
Description string `json:"description,omitempty"`
|
|
Category CourseCategory `json:"category" binding:"required"`
|
|
DurationMinutes int `json:"duration_minutes"`
|
|
RequiredForRoles []string `json:"required_for_roles,omitempty"`
|
|
Lessons []CreateLessonRequest `json:"lessons,omitempty"`
|
|
}
|
|
|
|
// CreateLessonRequest is the API request for creating a lesson
|
|
type CreateLessonRequest struct {
|
|
Title string `json:"title" binding:"required"`
|
|
Description string `json:"description,omitempty"`
|
|
LessonType LessonType `json:"lesson_type" binding:"required"`
|
|
ContentURL string `json:"content_url,omitempty"`
|
|
DurationMinutes int `json:"duration_minutes"`
|
|
OrderIndex int `json:"order_index"`
|
|
QuizQuestions []QuizQuestion `json:"quiz_questions,omitempty"`
|
|
}
|
|
|
|
// UpdateCourseRequest is the API request for updating a course
|
|
type UpdateCourseRequest struct {
|
|
Title *string `json:"title,omitempty"`
|
|
Description *string `json:"description,omitempty"`
|
|
Category *CourseCategory `json:"category,omitempty"`
|
|
DurationMinutes *int `json:"duration_minutes,omitempty"`
|
|
RequiredForRoles []string `json:"required_for_roles,omitempty"`
|
|
IsActive *bool `json:"is_active,omitempty"`
|
|
}
|
|
|
|
// EnrollUserRequest is the API request for enrolling a user in a course
|
|
type EnrollUserRequest struct {
|
|
CourseID uuid.UUID `json:"course_id" binding:"required"`
|
|
UserID uuid.UUID `json:"user_id" binding:"required"`
|
|
UserName string `json:"user_name" binding:"required"`
|
|
UserEmail string `json:"user_email" binding:"required"`
|
|
Deadline *time.Time `json:"deadline,omitempty"`
|
|
}
|
|
|
|
// UpdateProgressRequest is the API request for updating enrollment progress
|
|
type UpdateProgressRequest struct {
|
|
Progress int `json:"progress" binding:"required"`
|
|
CurrentLesson int `json:"current_lesson"`
|
|
}
|
|
|
|
// SubmitQuizRequest is the API request for submitting quiz answers
|
|
type SubmitQuizRequest struct {
|
|
LessonID uuid.UUID `json:"lesson_id" binding:"required"`
|
|
Answers []int `json:"answers" binding:"required"` // Index of selected answer per question
|
|
}
|
|
|
|
// SubmitQuizResponse is the API response for quiz submission
|
|
type SubmitQuizResponse struct {
|
|
Score int `json:"score"` // 0-100
|
|
Passed bool `json:"passed"`
|
|
CorrectAnswers int `json:"correct_answers"`
|
|
TotalQuestions int `json:"total_questions"`
|
|
Results []QuizResult `json:"results"`
|
|
}
|
|
|
|
// QuizResult represents the result for a single quiz question
|
|
type QuizResult struct {
|
|
Question string `json:"question"`
|
|
Correct bool `json:"correct"`
|
|
Explanation string `json:"explanation"`
|
|
}
|
|
|
|
// CourseListResponse is the API response for listing courses
|
|
type CourseListResponse struct {
|
|
Courses []Course `json:"courses"`
|
|
Total int `json:"total"`
|
|
}
|
|
|
|
// EnrollmentListResponse is the API response for listing enrollments
|
|
type EnrollmentListResponse struct {
|
|
Enrollments []Enrollment `json:"enrollments"`
|
|
Total int `json:"total"`
|
|
}
|