From 89af88ef7dcfe741d902fa8f4934c5d04aa1b4bb Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Fri, 8 May 2026 01:02:41 +0200 Subject: [PATCH] feat: Fortschritts-Tracker + Verifikation-Endpoints + Tech-File Erweiterung MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Übersicht: Completeness Gates durch Projektfortschritts-Tracker ersetzt (6 CE-Prozessschritte mit Status + Naechster-Schritt Empfehlung) - Verifikation: GET/POST/DELETE /verifications Endpoints + Alias-Handler - Tech-File: Anhang IV Struktur-Erweiterung - Maßnahmen: Expandable Details vorbereitet Co-Authored-By: Claude Opus 4.6 (1M context) --- .../sdk/iace/[projectId]/mitigations/page.tsx | 61 +++--- .../app/sdk/iace/[projectId]/page.tsx | 103 +++++------ .../sdk/iace/[projectId]/tech-file/page.tsx | 77 ++++++-- .../api/handlers/iace_handler_mitigations.go | 175 ------------------ .../api/handlers/iace_handler_techfile.go | 30 ++- ai-compliance-sdk/internal/app/routes.go | 4 + .../internal/iace/store_evidence.go | 9 + .../iace/tech_file_generator_prompts.go | 5 + 8 files changed, 184 insertions(+), 280 deletions(-) diff --git a/admin-compliance/app/sdk/iace/[projectId]/mitigations/page.tsx b/admin-compliance/app/sdk/iace/[projectId]/mitigations/page.tsx index 8332891..8b9b327 100644 --- a/admin-compliance/app/sdk/iace/[projectId]/mitigations/page.tsx +++ b/admin-compliance/app/sdk/iace/[projectId]/mitigations/page.tsx @@ -48,6 +48,7 @@ export default function MitigationsPage() { const [mitPages, setMitPages] = useState>({ design: 1, protection: 1, information: 1 }) const [selected, setSelected] = useState>(new Set()) const [batchAction, setBatchAction] = useState<'verify' | 'delete' | null>(null) + const [expandedMeasure, setExpandedMeasure] = useState(null) function toggleSection(type: string) { setExpanded((prev) => ({ ...prev, [type]: !prev[type] })) @@ -203,31 +204,45 @@ export default function MitigationsPage() {
Status
{/* Rows β€” paginated */} - {items.slice(0, (mitPages[type] || 1) * 50).map((m) => ( -
-
- toggleSelect(m.id)} - className="accent-purple-600" /> -
-
-
{m.title || ''}
- {m.description &&
{m.description}
} - {(() => { - const refs = measureNorms[(m.title || '').toLowerCase()] - return refs?.length > 0 ? ( -
Normen: {refs.join(', ')}
- ) : null - })()} -
-
- {(m.linked_hazard_names || []).join(', ') || '-'} -
-
- + {items.slice(0, (mitPages[type] || 1) * 50).map((m) => { + const isDetailOpen = expandedMeasure === m.id + const catMatch = (m.description || '').match(/Kategorie\s+(\S+)/) + const category = catMatch?.[1] + const refs = measureNorms[(m.title || '').toLowerCase()] + return ( +
+
setExpandedMeasure(isDetailOpen ? null : m.id)} + className={`grid grid-cols-[24px_2fr_1fr_80px] gap-2 px-4 py-2 border-t border-gray-50 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-750 transition-colors cursor-pointer ${selected.has(m.id) ? 'bg-purple-50 dark:bg-purple-900/10' : ''}`}> +
e.stopPropagation()}> + toggleSelect(m.id)} + className="accent-purple-600" /> +
+
+ + + +
+
{m.title || ''}
+ {!isDetailOpen && category &&
Kategorie: {category}
} +
+
+
+ {(m.linked_hazard_names || []).join(', ') || '-'} +
+
+ +
+ {isDetailOpen && ( +
+ {m.description &&

{m.description}

} + {category &&

Diese Massnahme gilt fuer alle Gefaehrdungen der Kategorie {category}.

} + {refs?.length > 0 &&

Normen: {refs.join(', ')}

} +
+ )}
- ))} + ) + })} {items.length > (mitPages[type] || 1) * 50 && (
- {/* Completeness Gates */} + {/* Progress Tracker */}
-

Completeness Gates

-
- {project.gates && project.gates.length > 0 ? ( - project.gates.map((gate) => ) - ) : ( -

Keine Gates definiert

- )} +
+

Projektfortschritt

+ {project.completeness_pct}% +
+
+
+
+
+ {(() => { + const hasLimits = Object.keys(project.metadata?.limits_form || {}).length > 0 + const steps = [ + { done: hasLimits, label: 'Grenzen definiert', detail: hasLimits ? 'Felder ausgefuellt' : 'ausstehend' }, + { done: project.component_count > 0, label: 'Komponenten erfasst', detail: `${project.component_count} Komponenten` }, + { done: project.hazard_count > 0, label: 'Gefaehrdungen identifiziert', detail: `${project.hazard_count} bewertet` }, + { done: project.mitigation_count > 0, label: 'Massnahmen zugeordnet', detail: `${project.mitigation_count} Massnahmen` }, + { done: false, label: 'Verifikation', detail: 'ausstehend' }, + { done: false, label: 'CE-Akte', detail: 'ausstehend' }, + ] + const firstPending = steps.find((s) => !s.done) + return ( + <> + {steps.map((step) => ( +
+ + {step.done ? '\u2713' : '\u25CB'} + + {step.label} + {step.detail} +
+ ))} +
+ Naechster Schritt: {firstPending?.label || 'Alle Schritte abgeschlossen'} +
+ + ) + })()}
diff --git a/admin-compliance/app/sdk/iace/[projectId]/tech-file/page.tsx b/admin-compliance/app/sdk/iace/[projectId]/tech-file/page.tsx index d669c00..7fb6416 100644 --- a/admin-compliance/app/sdk/iace/[projectId]/tech-file/page.tsx +++ b/admin-compliance/app/sdk/iace/[projectId]/tech-file/page.tsx @@ -19,21 +19,51 @@ interface TechFileSection { } const SECTION_TYPES: Record = { - risk_assessment_report: { - icon: 'πŸ“Š', - description: 'Zusammenfassung der Risikobeurteilung mit allen bewerteten Gefaehrdungen', + // Annex IV mandatory sections (EU Machinery Regulation 2023/1230) + general_description: { + icon: '🏭', + description: 'Anhang IV.1 β€” Allgemeine Beschreibung der Maschine mit bestimmungsgemaesser Verwendung', }, - hazard_log: { - icon: '⚠️', - description: 'Vollstaendiges Gefaehrdungsprotokoll mit S/E/P-Bewertungen', + design_specifications: { + icon: 'πŸ“', + description: 'Anhang IV.2 β€” Gesamtplan, Schaltplaene und Systemarchitektur', }, component_list: { icon: 'πŸ”§', - description: 'Verzeichnis aller sicherheitsrelevanten Komponenten', + description: 'Anhang IV.3 β€” Detailplaene und Verzeichnis aller sicherheitsrelevanten Komponenten', }, - classification_report: { + risk_assessment_report: { + icon: 'πŸ“Š', + description: 'Anhang IV.4 β€” Risikobeurteilung nach ISO 12100 mit allen bewerteten Gefaehrdungen', + }, + standards_applied: { + icon: 'πŸ“', + description: 'Anhang IV.5 β€” Angewandte harmonisierte Normen und deren Vermutungswirkung', + }, + test_reports: { + icon: 'πŸ§ͺ', + description: 'Anhang IV.6 β€” Pruefberichte und Verifikationsergebnisse', + }, + instructions_for_use: { + icon: 'πŸ“–', + description: 'Anhang IV.7 β€” Betriebsanleitung mit Sicherheitshinweisen', + }, + declaration_of_conformity: { + icon: 'πŸ“œ', + description: 'Anhang IV.8 β€” EU-Konformitaetserklaerung', + }, + assembly_declaration: { + icon: 'πŸ”©', + description: 'Anhang IV.9 β€” Einbauerklaerung fuer unvollstaendige Maschinen', + }, + // Supplementary CE-Akte sections + hazard_log_combined: { + icon: '⚠️', + description: 'Vollstaendiges Gefaehrdungsprotokoll (Hazard Log) mit S/E/P-Bewertungen', + }, + essential_requirements: { icon: 'πŸ“‹', - description: 'Regulatorische Klassifikation (AI Act, MVO, CRA, NIS2)', + description: 'Grundlegende Anforderungen (EHSR) nach MVO Anhang III', }, mitigation_report: { icon: 'πŸ›‘οΈ', @@ -47,17 +77,30 @@ const SECTION_TYPES: Record = { icon: 'πŸ“Ž', description: 'Index aller Nachweisdokumente mit Verknuepfungen', }, - declaration_of_conformity: { - icon: 'πŸ“œ', - description: 'EU-Konformitaetserklaerung', - }, - instructions_for_use: { - icon: 'πŸ“–', - description: 'Sicherheitshinweise fuer Betriebsanleitung', + classification_report: { + icon: '🏷️', + description: 'Regulatorische Klassifikation (AI Act, MVO, CRA, NIS2)', }, monitoring_plan: { icon: 'πŸ“‘', - description: 'Post-Market Surveillance Plan', + description: 'Post-Market Surveillance und Ueberwachungsplan', + }, + // AI-specific sections (when AI components present) + ai_intended_purpose: { + icon: '🎯', + description: 'Bestimmungsgemaesser Zweck des KI-Systems (AI Act Art. 13)', + }, + ai_model_description: { + icon: '🧠', + description: 'KI-Modellbeschreibung, Trainingsdaten und Architektur', + }, + ai_risk_management: { + icon: 'βš™οΈ', + description: 'KI-Risikomanagementsystem (AI Act Art. 9)', + }, + ai_human_oversight: { + icon: 'πŸ‘οΈ', + description: 'Menschliche Aufsicht und Kontrollmassnahmen (AI Act Art. 14)', }, } diff --git a/ai-compliance-sdk/internal/api/handlers/iace_handler_mitigations.go b/ai-compliance-sdk/internal/api/handlers/iace_handler_mitigations.go index 942efec..d065db5 100644 --- a/ai-compliance-sdk/internal/api/handlers/iace_handler_mitigations.go +++ b/ai-compliance-sdk/internal/api/handlers/iace_handler_mitigations.go @@ -158,178 +158,3 @@ func (h *IACEHandler) VerifyMitigation(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"message": "mitigation verified"}) } - -// ============================================================================ -// Evidence & Verification -// ============================================================================ - -// UploadEvidence handles POST /projects/:id/evidence -// Creates a new evidence record for a project. -func (h *IACEHandler) UploadEvidence(c *gin.Context) { - projectID, err := uuid.Parse(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"}) - return - } - - var req struct { - MitigationID *uuid.UUID `json:"mitigation_id,omitempty"` - VerificationPlanID *uuid.UUID `json:"verification_plan_id,omitempty"` - FileName string `json:"file_name" binding:"required"` - FilePath string `json:"file_path" binding:"required"` - FileHash string `json:"file_hash" binding:"required"` - FileSize int64 `json:"file_size" binding:"required"` - MimeType string `json:"mime_type" binding:"required"` - Description string `json:"description,omitempty"` - } - if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - userID := rbac.GetUserID(c) - - evidence := &iace.Evidence{ - ProjectID: projectID, - MitigationID: req.MitigationID, - VerificationPlanID: req.VerificationPlanID, - FileName: req.FileName, - FilePath: req.FilePath, - FileHash: req.FileHash, - FileSize: req.FileSize, - MimeType: req.MimeType, - Description: req.Description, - UploadedBy: userID, - } - - if err := h.store.CreateEvidence(c.Request.Context(), evidence); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Audit trail - newVals, _ := json.Marshal(evidence) - h.store.AddAuditEntry( - c.Request.Context(), projectID, "evidence", evidence.ID, - iace.AuditActionCreate, userID.String(), nil, newVals, - ) - - c.JSON(http.StatusCreated, gin.H{"evidence": evidence}) -} - -// ListEvidence handles GET /projects/:id/evidence -// Lists all evidence records for a project. -func (h *IACEHandler) ListEvidence(c *gin.Context) { - projectID, err := uuid.Parse(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"}) - return - } - - evidence, err := h.store.ListEvidence(c.Request.Context(), projectID) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - if evidence == nil { - evidence = []iace.Evidence{} - } - - c.JSON(http.StatusOK, gin.H{ - "evidence": evidence, - "total": len(evidence), - }) -} - -// CreateVerificationPlan handles POST /projects/:id/verification-plan -// Creates a new verification plan for a project. -func (h *IACEHandler) CreateVerificationPlan(c *gin.Context) { - projectID, err := uuid.Parse(c.Param("id")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid project ID"}) - return - } - - var req iace.CreateVerificationPlanRequest - if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - // Override project ID from URL path - req.ProjectID = projectID - - plan, err := h.store.CreateVerificationPlan(c.Request.Context(), req) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - // Audit trail - userID := rbac.GetUserID(c) - newVals, _ := json.Marshal(plan) - h.store.AddAuditEntry( - c.Request.Context(), projectID, "verification_plan", plan.ID, - iace.AuditActionCreate, userID.String(), nil, newVals, - ) - - c.JSON(http.StatusCreated, gin.H{"verification_plan": plan}) -} - -// UpdateVerificationPlan handles PUT /verification-plan/:vid -// Updates a verification plan with the provided fields. -func (h *IACEHandler) UpdateVerificationPlan(c *gin.Context) { - planID, err := uuid.Parse(c.Param("vid")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid verification plan ID"}) - return - } - - var updates map[string]interface{} - if err := c.ShouldBindJSON(&updates); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - plan, err := h.store.UpdateVerificationPlan(c.Request.Context(), planID, updates) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - if plan == nil { - c.JSON(http.StatusNotFound, gin.H{"error": "verification plan not found"}) - return - } - - c.JSON(http.StatusOK, gin.H{"verification_plan": plan}) -} - -// CompleteVerification handles POST /verification-plan/:vid/complete -// Marks a verification plan as completed with a result. -func (h *IACEHandler) CompleteVerification(c *gin.Context) { - planID, err := uuid.Parse(c.Param("vid")) - if err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": "invalid verification plan ID"}) - return - } - - var req struct { - Result string `json:"result" binding:"required"` - } - if err := c.ShouldBindJSON(&req); err != nil { - c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - return - } - - userID := rbac.GetUserID(c) - - if err := h.store.CompleteVerification( - c.Request.Context(), planID, req.Result, userID.String(), - ); err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - return - } - - c.JSON(http.StatusOK, gin.H{"message": "verification completed"}) -} diff --git a/ai-compliance-sdk/internal/api/handlers/iace_handler_techfile.go b/ai-compliance-sdk/internal/api/handlers/iace_handler_techfile.go index 8442c8f..41452b9 100644 --- a/ai-compliance-sdk/internal/api/handlers/iace_handler_techfile.go +++ b/ai-compliance-sdk/internal/api/handlers/iace_handler_techfile.go @@ -35,19 +35,30 @@ func (h *IACEHandler) GenerateTechFile(c *gin.Context) { return } - // Define the standard CE technical file sections to generate + // Define sections per EU Machinery Regulation 2023/1230 Annex IV structure. + // Core Annex IV sections come first, then supplementary CE-Akte sections. sectionDefinitions := []struct { SectionType string Title string }{ - {"general_description", "General Description of the Machinery"}, - {"risk_assessment_report", "Risk Assessment Report"}, - {"hazard_log_combined", "Combined Hazard Log"}, - {"essential_requirements", "Essential Health and Safety Requirements"}, - {"design_specifications", "Design Specifications and Drawings"}, - {"test_reports", "Test Reports and Verification Results"}, - {"standards_applied", "Applied Harmonised Standards"}, - {"declaration_of_conformity", "EU Declaration of Conformity"}, + // Annex IV mandatory sections + {"general_description", "Anhang IV.1 β€” Allgemeine Beschreibung der Maschine"}, + {"design_specifications", "Anhang IV.2 β€” Gesamtplan und Schaltplaene"}, + {"component_list", "Anhang IV.3 β€” Detailplaene und Komponentenliste"}, + {"risk_assessment_report", "Anhang IV.4 β€” Risikobeurteilung"}, + {"standards_applied", "Anhang IV.5 β€” Angewandte harmonisierte Normen"}, + {"test_reports", "Anhang IV.6 β€” Pruefberichte und Ergebnisse"}, + {"instructions_for_use", "Anhang IV.7 β€” Betriebsanleitung"}, + {"declaration_of_conformity", "Anhang IV.8 β€” EU-Konformitaetserklaerung"}, + {"assembly_declaration", "Anhang IV.9 β€” Einbauerklaerung (falls zutreffend)"}, + // Supplementary CE-Akte sections + {"hazard_log_combined", "Gefaehrdungsprotokoll (Hazard Log)"}, + {"essential_requirements", "Grundlegende Anforderungen (EHSR)"}, + {"mitigation_report", "Massnahmenbericht (3-Stufen-Verfahren)"}, + {"verification_report", "Verifikationsbericht"}, + {"evidence_index", "Nachweisverzeichnis"}, + {"classification_report", "Regulatorischer Klassifizierungsbericht"}, + {"monitoring_plan", "Post-Market-Monitoring-Plan"}, } // Check if project has AI components for additional sections @@ -184,6 +195,7 @@ func (h *IACEHandler) GenerateSingleSection(c *gin.Context) { "evidence_index": "Evidence Index", "instructions_for_use": "Instructions for Use", "monitoring_plan": "Post-Market Monitoring Plan", + "assembly_declaration": "Anhang IV.9 β€” Einbauerklaerung (falls zutreffend)", "ai_intended_purpose": "AI System Intended Purpose", "ai_model_description": "AI Model Description and Training Data", "ai_risk_management": "AI Risk Management System", diff --git a/ai-compliance-sdk/internal/app/routes.go b/ai-compliance-sdk/internal/app/routes.go index 497060b..bc20c77 100644 --- a/ai-compliance-sdk/internal/app/routes.go +++ b/ai-compliance-sdk/internal/app/routes.go @@ -403,6 +403,10 @@ func registerIACERoutes(v1 *gin.RouterGroup, h *handlers.IACEHandler) { iaceRoutes.POST("/projects/:id/verification-plan", h.CreateVerificationPlan) iaceRoutes.PUT("/verification-plan/:vid", h.UpdateVerificationPlan) iaceRoutes.POST("/verification-plan/:vid/complete", h.CompleteVerification) + iaceRoutes.GET("/projects/:id/verifications", h.ListVerificationPlans) + iaceRoutes.POST("/projects/:id/verifications", h.CreateVerificationAlias) + iaceRoutes.DELETE("/projects/:id/verifications/:vid", h.DeleteVerificationPlan) + iaceRoutes.POST("/projects/:id/verifications/:vid/complete", h.CompleteVerificationAlias) iaceRoutes.POST("/projects/:id/tech-file/generate", h.GenerateTechFile) iaceRoutes.GET("/projects/:id/tech-file", h.ListTechFileSections) iaceRoutes.PUT("/projects/:id/tech-file/:section", h.UpdateTechFileSection) diff --git a/ai-compliance-sdk/internal/iace/store_evidence.go b/ai-compliance-sdk/internal/iace/store_evidence.go index e2017b0..65df23f 100644 --- a/ai-compliance-sdk/internal/iace/store_evidence.go +++ b/ai-compliance-sdk/internal/iace/store_evidence.go @@ -247,6 +247,15 @@ func (s *Store) getVerificationPlan(ctx context.Context, id uuid.UUID) (*Verific return &vp, nil } +// DeleteVerificationPlan deletes a verification plan by ID +func (s *Store) DeleteVerificationPlan(ctx context.Context, id uuid.UUID) error { + _, err := s.pool.Exec(ctx, `DELETE FROM iace_verification_plans WHERE id = $1`, id) + if err != nil { + return fmt.Errorf("delete verification plan: %w", err) + } + return nil +} + // ============================================================================ // Reference Data Operations // ============================================================================ diff --git a/ai-compliance-sdk/internal/iace/tech_file_generator_prompts.go b/ai-compliance-sdk/internal/iace/tech_file_generator_prompts.go index 2722ced..f76eff5 100644 --- a/ai-compliance-sdk/internal/iace/tech_file_generator_prompts.go +++ b/ai-compliance-sdk/internal/iace/tech_file_generator_prompts.go @@ -24,6 +24,7 @@ const ( SectionEvidenceIndex = "evidence_index" SectionInstructionsForUse = "instructions_for_use" SectionMonitoringPlan = "monitoring_plan" + SectionAssemblyDeclaration = "assembly_declaration" ) // ============================================================================ @@ -68,6 +69,8 @@ var sectionSystemPrompts = map[string]string{ SectionInstructionsForUse: `Erstelle eine Gliederung fuer die Betriebsanleitung gemaess EU-Maschinenverordnung 2023/1230 Anhang III Abschnitt 1.7.4. Enthalten: 1) Bestimmungsgemaesse Verwendung, 2) Inbetriebnahme, 3) Sicherer Betrieb, 4) Wartung, 5) Restrisiken und Warnhinweise, 6) Ausserbetriebnahme. Beruecksichtige identifizierte Gefaehrdungen.`, SectionMonitoringPlan: `Erstelle einen Post-Market-Monitoring-Plan fuer das Produkt. Enthalten: 1) Ueberwachungsziele, 2) Datenquellen (Kundenfeedback, Vorfaelle, Updates), 3) Ueberwachungsintervalle, 4) Eskalationsverfahren, 5) Dokumentationspflichten, 6) Verantwortlichkeiten. Beruecksichtige AI Act Art. 72 (Post-Market Monitoring) falls KI-Komponenten vorhanden.`, + + SectionAssemblyDeclaration: `Erstelle eine Einbauerklaerung gemaess EU-Maschinenverordnung 2023/1230 Anhang IV.9 fuer eine unvollstaendige Maschine. Enthalten: 1) Hersteller-Angaben, 2) Bezeichnung der unvollstaendigen Maschine, 3) Erklaerung, dass die Inbetriebnahme untersagt ist bis die Gesamtmaschine konform erklaert wurde, 4) Liste der eingehaltenen Anforderungen, 5) Angaben zur technischen Dokumentation. Falls die Maschine vollstaendig ist, vermerke "Nicht zutreffend β€” vollstaendige Maschine".`, } // ============================================================================ @@ -95,6 +98,7 @@ func buildRAGQuery(sectionType string) string { SectionEvidenceIndex: "Nachweisdokumente Evidence Konformitaetsnachweis Dokumentenindex", SectionInstructionsForUse: "Betriebsanleitung Benutzerinformation Maschinenverordnung Abschnitt 1.7.4 Sicherheitshinweise", SectionMonitoringPlan: "Post-Market-Monitoring Ueberwachungsplan AI Act Art. 72 Marktbeobachtung", + SectionAssemblyDeclaration: "Einbauerklaerung unvollstaendige Maschine Maschinenverordnung Anhang IV", } if q, ok := ragQueries[sectionType]; ok { @@ -133,6 +137,7 @@ func sectionDisplayName(sectionType string) string { SectionEvidenceIndex: "Nachweisverzeichnis", SectionInstructionsForUse: "Betriebsanleitung (Gliederung)", SectionMonitoringPlan: "Post-Market-Monitoring-Plan", + SectionAssemblyDeclaration: "Einbauerklaerung", } if name, ok := names[sectionType]; ok { return name