feat: Implement Compliance Academy E-Learning module (Phases 1-7)
Some checks 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 / 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
ci/woodpecker/push/integration Pipeline failed
ci/woodpecker/push/main Pipeline failed
Security Scanning / Secret Scanning (push) Has been cancelled
Security Scanning / Dependency Vulnerability Scan (push) Has been cancelled
Security Scanning / Docker Image Security (push) Has been cancelled
Tests / Go Lint (push) Has been cancelled
Tests / All Checks Passed (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 / Python Lint (push) Has been cancelled
Tests / Security Scan (push) Has been cancelled

Add complete Academy backend (Go) and frontend (Next.js) for DSGVO/IT-Security/AI-Literacy compliance training:
- Go backend: Course CRUD, enrollments, quiz evaluation, PDF certificates (gofpdf), video generation pipeline (ElevenLabs + HeyGen)
- In-memory data store with PostgreSQL migration for future DB support
- Frontend: Course creation (AI + manual), lesson viewer, interactive quiz, certificate viewer with PDF download
- Fix existing compile errors in generate.go (SearchResult type mismatch), llm/service.go (unused var), rag/service.go (Unicode chars)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
BreakPilot Dev
2026-02-14 21:18:51 +01:00
parent 71cde313d5
commit ac1bb1d97b
19 changed files with 4070 additions and 22 deletions

View File

@@ -31,15 +31,15 @@ func (h *GenerateHandler) GenerateDSFA(c *gin.Context) {
}
// Get RAG context if requested
var ragSources []SearchResult
var ragSources []llm.SearchResult
if req.UseRAG && h.ragService != nil {
query := req.RAGQuery
if query == "" {
query = "DSFA Datenschutz-Folgenabschätzung Anforderungen"
query = "DSFA Datenschutz-Folgenabschaetzung Anforderungen"
}
results, _ := h.ragService.Search(c.Request.Context(), query, 5, "legal_corpus", "regulation:DSGVO")
for _, r := range results {
ragSources = append(ragSources, SearchResult{
ragSources = append(ragSources, llm.SearchResult{
ID: r.ID,
Content: r.Content,
Source: r.Source,
@@ -62,7 +62,7 @@ func (h *GenerateHandler) GenerateDSFA(c *gin.Context) {
GeneratedAt: now(),
Model: h.llmService.GetModel(),
TokensUsed: tokensUsed,
RAGSources: ragSources,
RAGSources: convertLLMSources(ragSources),
Confidence: 0.85,
})
}
@@ -76,15 +76,15 @@ func (h *GenerateHandler) GenerateTOM(c *gin.Context) {
}
// Get RAG context if requested
var ragSources []SearchResult
var llmRagSources []llm.SearchResult
if req.UseRAG && h.ragService != nil {
query := req.RAGQuery
if query == "" {
query = "technische organisatorische Maßnahmen TOM Datenschutz"
query = "technische organisatorische Massnahmen TOM Datenschutz"
}
results, _ := h.ragService.Search(c.Request.Context(), query, 5, "legal_corpus", "")
for _, r := range results {
ragSources = append(ragSources, SearchResult{
llmRagSources = append(llmRagSources, llm.SearchResult{
ID: r.ID,
Content: r.Content,
Source: r.Source,
@@ -95,7 +95,7 @@ func (h *GenerateHandler) GenerateTOM(c *gin.Context) {
}
// Generate TOM content
content, tokensUsed, err := h.llmService.GenerateTOM(c.Request.Context(), req.Context, ragSources)
content, tokensUsed, err := h.llmService.GenerateTOM(c.Request.Context(), req.Context, llmRagSources)
if err != nil {
content = h.getMockTOM(req.Context)
tokensUsed = 0
@@ -106,7 +106,7 @@ func (h *GenerateHandler) GenerateTOM(c *gin.Context) {
GeneratedAt: now(),
Model: h.llmService.GetModel(),
TokensUsed: tokensUsed,
RAGSources: ragSources,
RAGSources: convertLLMSources(llmRagSources),
Confidence: 0.82,
})
}
@@ -120,7 +120,7 @@ func (h *GenerateHandler) GenerateVVT(c *gin.Context) {
}
// Get RAG context if requested
var ragSources []SearchResult
var llmRagSources []llm.SearchResult
if req.UseRAG && h.ragService != nil {
query := req.RAGQuery
if query == "" {
@@ -128,7 +128,7 @@ func (h *GenerateHandler) GenerateVVT(c *gin.Context) {
}
results, _ := h.ragService.Search(c.Request.Context(), query, 5, "legal_corpus", "regulation:DSGVO")
for _, r := range results {
ragSources = append(ragSources, SearchResult{
llmRagSources = append(llmRagSources, llm.SearchResult{
ID: r.ID,
Content: r.Content,
Source: r.Source,
@@ -139,7 +139,7 @@ func (h *GenerateHandler) GenerateVVT(c *gin.Context) {
}
// Generate VVT content
content, tokensUsed, err := h.llmService.GenerateVVT(c.Request.Context(), req.Context, ragSources)
content, tokensUsed, err := h.llmService.GenerateVVT(c.Request.Context(), req.Context, llmRagSources)
if err != nil {
content = h.getMockVVT(req.Context)
tokensUsed = 0
@@ -150,7 +150,7 @@ func (h *GenerateHandler) GenerateVVT(c *gin.Context) {
GeneratedAt: now(),
Model: h.llmService.GetModel(),
TokensUsed: tokensUsed,
RAGSources: ragSources,
RAGSources: convertLLMSources(llmRagSources),
Confidence: 0.88,
})
}
@@ -164,7 +164,7 @@ func (h *GenerateHandler) GenerateGutachten(c *gin.Context) {
}
// Get RAG context if requested
var ragSources []SearchResult
var llmRagSources []llm.SearchResult
if req.UseRAG && h.ragService != nil {
query := req.RAGQuery
if query == "" {
@@ -172,7 +172,7 @@ func (h *GenerateHandler) GenerateGutachten(c *gin.Context) {
}
results, _ := h.ragService.Search(c.Request.Context(), query, 5, "legal_corpus", "")
for _, r := range results {
ragSources = append(ragSources, SearchResult{
llmRagSources = append(llmRagSources, llm.SearchResult{
ID: r.ID,
Content: r.Content,
Source: r.Source,
@@ -183,7 +183,7 @@ func (h *GenerateHandler) GenerateGutachten(c *gin.Context) {
}
// Generate Gutachten content
content, tokensUsed, err := h.llmService.GenerateGutachten(c.Request.Context(), req.Context, ragSources)
content, tokensUsed, err := h.llmService.GenerateGutachten(c.Request.Context(), req.Context, llmRagSources)
if err != nil {
content = h.getMockGutachten(req.Context)
tokensUsed = 0
@@ -194,7 +194,7 @@ func (h *GenerateHandler) GenerateGutachten(c *gin.Context) {
GeneratedAt: now(),
Model: h.llmService.GetModel(),
TokensUsed: tokensUsed,
RAGSources: ragSources,
RAGSources: convertLLMSources(llmRagSources),
Confidence: 0.80,
})
}
@@ -363,3 +363,21 @@ Das geprüfte KI-System erfüllt die wesentlichen Anforderungen der DSGVO und de
Erstellt am: ${new Date().toISOString()}
`
}
// convertLLMSources converts llm.SearchResult to api.SearchResult for the response
func convertLLMSources(sources []llm.SearchResult) []SearchResult {
if sources == nil {
return nil
}
result := make([]SearchResult, len(sources))
for i, s := range sources {
result[i] = SearchResult{
ID: s.ID,
Content: s.Content,
Source: s.Source,
Score: s.Score,
Metadata: s.Metadata,
}
}
return result
}