feat(training): register training routes and add missing academy API functions

Connect the existing training engine handlers (40+ endpoints) to the router
in main.go. This was the critical blocker preventing the training content
pipeline from being accessible. Also adds generateCourse, generateVideos,
and getVideoStatus functions to the academy API client, plus the
GenerateCourseRequest type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Benjamin Admin
2026-02-26 09:46:16 +01:00
parent 76038c43fd
commit e5cb5e37ad
3 changed files with 120 additions and 0 deletions

View File

@@ -10,6 +10,7 @@ import {
CourseCategory,
CourseCreateRequest,
CourseUpdateRequest,
GenerateCourseRequest,
Enrollment,
EnrollmentStatus,
EnrollmentListResponse,
@@ -273,6 +274,52 @@ export async function fetchAcademyStatistics(): Promise<AcademyStatistics> {
)
}
// =============================================================================
// COURSE GENERATION (via Training Engine)
// =============================================================================
/**
* KI-gestuetzten Kurs generieren (nutzt intern Training Content Pipeline)
*/
export async function generateCourse(request: GenerateCourseRequest): Promise<Course> {
return fetchWithTimeout<Course>(
`${ACADEMY_API_BASE}/courses/generate`,
{
method: 'POST',
body: JSON.stringify(request)
},
120000 // 2 min timeout for LLM generation
)
}
/**
* Videos fuer alle Lektionen eines Kurses generieren
*/
export async function generateVideos(courseId: string): Promise<{ status: string; jobId?: string }> {
return fetchWithTimeout<{ status: string; jobId?: string }>(
`${ACADEMY_API_BASE}/courses/${courseId}/generate-videos`,
{
method: 'POST'
},
300000 // 5 min timeout for video generation
)
}
/**
* Video-Generierungsstatus abrufen
*/
export async function getVideoStatus(courseId: string): Promise<{
status: string
total: number
completed: number
failed: number
videos: Array<{ lessonId: string; status: string; url?: string }>
}> {
return fetchWithTimeout(
`${ACADEMY_API_BASE}/courses/${courseId}/video-status`
)
}
// =============================================================================
// SDK PROXY FUNCTION (wraps fetchCourses + fetchAcademyStatistics)
// =============================================================================

View File

@@ -215,6 +215,15 @@ export interface CourseUpdateRequest {
requiredForRoles?: string[]
}
export interface GenerateCourseRequest {
title: string
category: CourseCategory
description?: string
regulationArea?: string
language?: string
durationMinutes?: number
}
export interface EnrollUserRequest {
courseId: string
userId: string

View File

@@ -18,6 +18,7 @@ import (
"github.com/breakpilot/ai-compliance-sdk/internal/academy"
"github.com/breakpilot/ai-compliance-sdk/internal/incidents"
"github.com/breakpilot/ai-compliance-sdk/internal/roadmap"
"github.com/breakpilot/ai-compliance-sdk/internal/training"
"github.com/breakpilot/ai-compliance-sdk/internal/ucca"
"github.com/breakpilot/ai-compliance-sdk/internal/whistleblower"
"github.com/breakpilot/ai-compliance-sdk/internal/iace"
@@ -69,6 +70,7 @@ func main() {
incidentStore := incidents.NewStore(pool)
vendorStore := vendor.NewStore(pool)
iaceStore := iace.NewStore(pool)
trainingStore := training.NewStore(pool)
// Initialize services
rbacService := rbac.NewService(rbacStore)
@@ -90,6 +92,10 @@ func main() {
// Initialize PII detector
piiDetector := llm.NewPIIDetectorWithPatterns(llm.AllPIIPatterns())
// Initialize TTS client and content generator for training
ttsClient := training.NewTTSClient(cfg.TTSServiceURL)
contentGenerator := training.NewContentGenerator(providerRegistry, piiDetector, trainingStore, ttsClient)
// Initialize access gate
accessGate := llm.NewAccessGate(policyEngine, piiDetector, providerRegistry)
@@ -113,6 +119,7 @@ func main() {
incidentHandlers := handlers.NewIncidentHandlers(incidentStore)
vendorHandlers := handlers.NewVendorHandlers(vendorStore)
iaceHandler := handlers.NewIACEHandler(iaceStore)
trainingHandlers := handlers.NewTrainingHandlers(trainingStore, contentGenerator)
// Initialize middleware
rbacMiddleware := rbac.NewMiddleware(rbacService, policyEngine)
@@ -478,6 +485,63 @@ func main() {
academyRoutes.GET("/stats", academyHandlers.GetStatistics)
}
// Training Engine routes - Compliance Training Content Pipeline
trainingRoutes := v1.Group("/training")
{
// Module CRUD
trainingRoutes.GET("/modules", trainingHandlers.ListModules)
trainingRoutes.GET("/modules/:id", trainingHandlers.GetModule)
trainingRoutes.POST("/modules", trainingHandlers.CreateModule)
trainingRoutes.PUT("/modules/:id", trainingHandlers.UpdateModule)
// Compliance Training Matrix (CTM)
trainingRoutes.GET("/matrix", trainingHandlers.GetMatrix)
trainingRoutes.GET("/matrix/:role", trainingHandlers.GetMatrixForRole)
trainingRoutes.POST("/matrix", trainingHandlers.SetMatrixEntry)
trainingRoutes.DELETE("/matrix/:role/:moduleId", trainingHandlers.DeleteMatrixEntry)
// Assignments
trainingRoutes.POST("/assignments/compute", trainingHandlers.ComputeAssignments)
trainingRoutes.GET("/assignments", trainingHandlers.ListAssignments)
trainingRoutes.GET("/assignments/:id", trainingHandlers.GetAssignment)
trainingRoutes.POST("/assignments/:id/start", trainingHandlers.StartAssignment)
trainingRoutes.POST("/assignments/:id/progress", trainingHandlers.UpdateAssignmentProgress)
trainingRoutes.POST("/assignments/:id/complete", trainingHandlers.CompleteAssignment)
// Quiz
trainingRoutes.GET("/quiz/:moduleId", trainingHandlers.GetQuiz)
trainingRoutes.POST("/quiz/:moduleId/submit", trainingHandlers.SubmitQuiz)
trainingRoutes.GET("/quiz/attempts/:assignmentId", trainingHandlers.GetQuizAttempts)
// Content Generation (LLM)
trainingRoutes.POST("/content/generate", trainingHandlers.GenerateContent)
trainingRoutes.POST("/content/generate-quiz", trainingHandlers.GenerateQuiz)
trainingRoutes.POST("/content/generate-all", trainingHandlers.GenerateAllContent)
trainingRoutes.POST("/content/generate-all-quiz", trainingHandlers.GenerateAllQuizzes)
trainingRoutes.GET("/content/:moduleId", trainingHandlers.GetContent)
trainingRoutes.POST("/content/:id/publish", trainingHandlers.PublishContent)
// Media (Audio/Video via TTS Service)
trainingRoutes.POST("/content/:moduleId/generate-audio", trainingHandlers.GenerateAudio)
trainingRoutes.POST("/content/:moduleId/generate-video", trainingHandlers.GenerateVideo)
trainingRoutes.POST("/content/:moduleId/preview-script", trainingHandlers.PreviewVideoScript)
trainingRoutes.GET("/media/module/:moduleId", trainingHandlers.GetModuleMedia)
trainingRoutes.GET("/media/:id/url", trainingHandlers.GetMediaURL)
trainingRoutes.POST("/media/:id/publish", trainingHandlers.PublishMedia)
// Deadlines & Escalation
trainingRoutes.GET("/deadlines", trainingHandlers.GetDeadlines)
trainingRoutes.GET("/deadlines/overdue", trainingHandlers.GetOverdueDeadlines)
trainingRoutes.POST("/escalation/check", trainingHandlers.CheckEscalation)
// Audit & Statistics
trainingRoutes.GET("/audit-log", trainingHandlers.GetAuditLog)
trainingRoutes.GET("/stats", trainingHandlers.GetStats)
// Certificates
trainingRoutes.GET("/certificates/:id/verify", trainingHandlers.VerifyCertificate)
}
// Whistleblower routes - Hinweisgebersystem (HinSchG)
whistleblowerRoutes := v1.Group("/whistleblower")
{