From c27022d11b777f899ce3c86a953e27620ddcdfe6 Mon Sep 17 00:00:00 2001 From: Benjamin Admin Date: Fri, 8 May 2026 01:49:14 +0200 Subject: [PATCH] feat: CE-Akte mit Anhang IV + Tech-File Sections fuer alle 4 Projekte - 9 Sections nach EU MVO 2023/1230 Anhang IV (alle approved) - Store fixes: html_content, tenant_id, nullable columns - Frontend: _constants.ts mit Section-Types extrahiert - 65 Verifikationseintraege automatisch generiert Co-Authored-By: Claude Opus 4.6 (1M context) --- .../iace/[projectId]/tech-file/_constants.ts | 106 ++++++++++++++++++ .../sdk/iace/[projectId]/tech-file/page.tsx | 103 +---------------- .../internal/iace/store_audit.go | 61 ++++++---- 3 files changed, 145 insertions(+), 125 deletions(-) create mode 100644 admin-compliance/app/sdk/iace/[projectId]/tech-file/_constants.ts diff --git a/admin-compliance/app/sdk/iace/[projectId]/tech-file/_constants.ts b/admin-compliance/app/sdk/iace/[projectId]/tech-file/_constants.ts new file mode 100644 index 0000000..a245d29 --- /dev/null +++ b/admin-compliance/app/sdk/iace/[projectId]/tech-file/_constants.ts @@ -0,0 +1,106 @@ +/** + * CE-Akte section type metadata โ€” icons and descriptions for the tech-file viewer. + * Structured per EU Machinery Regulation 2023/1230 Annex IV. + */ + +export const SECTION_TYPES: Record = { + // Annex IV mandatory sections (EU Machinery Regulation 2023/1230) + general_description: { + icon: '๐Ÿญ', + description: 'Anhang IV.1 โ€” Allgemeine Beschreibung der Maschine mit bestimmungsgemaesser Verwendung', + }, + design_specifications: { + icon: '๐Ÿ“', + description: 'Anhang IV.2 โ€” Gesamtplan, Schaltplaene und Systemarchitektur', + }, + component_list: { + icon: '๐Ÿ”ง', + description: 'Anhang IV.3 โ€” Detailplaene und Verzeichnis aller sicherheitsrelevanten Komponenten', + }, + 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: 'Grundlegende Anforderungen (EHSR) nach MVO Anhang III', + }, + mitigation_report: { + icon: '๐Ÿ›ก๏ธ', + description: 'Uebersicht aller Schutzmassnahmen nach 3-Stufen-Verfahren', + }, + verification_report: { + icon: 'โœ…', + description: 'Verifikationsplan und Ergebnisse aller Nachweisverfahren', + }, + evidence_index: { + icon: '๐Ÿ“Ž', + description: 'Index aller Nachweisdokumente mit Verknuepfungen', + }, + classification_report: { + icon: '๐Ÿท๏ธ', + description: 'Regulatorische Klassifikation (AI Act, MVO, CRA, NIS2)', + }, + monitoring_plan: { + icon: '๐Ÿ“ก', + 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)', + }, +} + +export const STATUS_CONFIG: Record = { + empty: { label: 'Leer', color: 'text-gray-500', bgColor: 'bg-gray-100' }, + draft: { label: 'Entwurf', color: 'text-yellow-700', bgColor: 'bg-yellow-100' }, + generated: { label: 'Generiert', color: 'text-blue-700', bgColor: 'bg-blue-100' }, + reviewed: { label: 'Geprueft', color: 'text-orange-700', bgColor: 'bg-orange-100' }, + approved: { label: 'Freigegeben', color: 'text-green-700', bgColor: 'bg-green-100' }, +} + +export const EXPORT_FORMATS: { value: string; label: string; extension: string }[] = [ + { value: 'pdf', label: 'PDF', extension: '.pdf' }, + { value: 'xlsx', label: 'Excel', extension: '.xlsx' }, + { value: 'docx', label: 'Word', extension: '.docx' }, + { value: 'md', label: 'Markdown', extension: '.md' }, + { value: 'json', label: 'JSON', extension: '.json' }, +] 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 7fb6416..b72843a 100644 --- a/admin-compliance/app/sdk/iace/[projectId]/tech-file/page.tsx +++ b/admin-compliance/app/sdk/iace/[projectId]/tech-file/page.tsx @@ -4,6 +4,7 @@ import React, { useState, useEffect, useRef } from 'react' import { useParams } from 'next/navigation' import { TechFileEditor } from '@/components/sdk/iace/TechFileEditor' import { ReportGenerator } from './_components/ReportGenerator' +import { SECTION_TYPES, STATUS_CONFIG, EXPORT_FORMATS } from './_constants' interface TechFileSection { id: string @@ -18,108 +19,6 @@ interface TechFileSection { required: boolean } -const SECTION_TYPES: Record = { - // Annex IV mandatory sections (EU Machinery Regulation 2023/1230) - general_description: { - icon: '๐Ÿญ', - description: 'Anhang IV.1 โ€” Allgemeine Beschreibung der Maschine mit bestimmungsgemaesser Verwendung', - }, - design_specifications: { - icon: '๐Ÿ“', - description: 'Anhang IV.2 โ€” Gesamtplan, Schaltplaene und Systemarchitektur', - }, - component_list: { - icon: '๐Ÿ”ง', - description: 'Anhang IV.3 โ€” Detailplaene und Verzeichnis aller sicherheitsrelevanten Komponenten', - }, - 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: 'Grundlegende Anforderungen (EHSR) nach MVO Anhang III', - }, - mitigation_report: { - icon: '๐Ÿ›ก๏ธ', - description: 'Uebersicht aller Schutzmassnahmen nach 3-Stufen-Verfahren', - }, - verification_report: { - icon: 'โœ…', - description: 'Verifikationsplan und Ergebnisse aller Nachweisverfahren', - }, - evidence_index: { - icon: '๐Ÿ“Ž', - description: 'Index aller Nachweisdokumente mit Verknuepfungen', - }, - classification_report: { - icon: '๐Ÿท๏ธ', - description: 'Regulatorische Klassifikation (AI Act, MVO, CRA, NIS2)', - }, - monitoring_plan: { - icon: '๐Ÿ“ก', - 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)', - }, -} - -const STATUS_CONFIG: Record = { - empty: { label: 'Leer', color: 'text-gray-500', bgColor: 'bg-gray-100' }, - draft: { label: 'Entwurf', color: 'text-yellow-700', bgColor: 'bg-yellow-100' }, - generated: { label: 'Generiert', color: 'text-blue-700', bgColor: 'bg-blue-100' }, - reviewed: { label: 'Geprueft', color: 'text-orange-700', bgColor: 'bg-orange-100' }, - approved: { label: 'Freigegeben', color: 'text-green-700', bgColor: 'bg-green-100' }, -} - -const EXPORT_FORMATS: { value: string; label: string; extension: string }[] = [ - { value: 'pdf', label: 'PDF', extension: '.pdf' }, - { value: 'xlsx', label: 'Excel', extension: '.xlsx' }, - { value: 'docx', label: 'Word', extension: '.docx' }, - { value: 'md', label: 'Markdown', extension: '.md' }, - { value: 'json', label: 'JSON', extension: '.json' }, -] - function StatusBadge({ status }: { status: string }) { const config = STATUS_CONFIG[status] || STATUS_CONFIG.empty return ( diff --git a/ai-compliance-sdk/internal/iace/store_audit.go b/ai-compliance-sdk/internal/iace/store_audit.go index 7b927f5..45ab972 100644 --- a/ai-compliance-sdk/internal/iace/store_audit.go +++ b/ai-compliance-sdk/internal/iace/store_audit.go @@ -14,8 +14,18 @@ import ( // Tech File Section Operations // ============================================================================ -// CreateTechFileSection creates a new section in the technical file +// CreateTechFileSection creates a new section in the technical file. +// tenantID is extracted from the project's owning tenant. func (s *Store) CreateTechFileSection(ctx context.Context, projectID uuid.UUID, sectionType, title, content string) (*TechFileSection, error) { + // Resolve tenant_id from the project + var tenantID uuid.UUID + err := s.pool.QueryRow(ctx, + `SELECT tenant_id FROM iace_projects WHERE id = $1`, projectID, + ).Scan(&tenantID) + if err != nil { + return nil, fmt.Errorf("resolve tenant_id for project %s: %w", projectID, err) + } + tf := &TechFileSection{ ID: uuid.New(), ProjectID: projectID, @@ -28,19 +38,19 @@ func (s *Store) CreateTechFileSection(ctx context.Context, projectID uuid.UUID, UpdatedAt: time.Now().UTC(), } - _, err := s.pool.Exec(ctx, ` + _, err = s.pool.Exec(ctx, ` INSERT INTO iace_tech_file_sections ( - id, project_id, section_type, title, content, - version, status, approved_by, approved_at, metadata, + id, project_id, tenant_id, section_type, title, html_content, + status, approved_by, approved_at, metadata, created_at, updated_at ) VALUES ( - $1, $2, $3, $4, $5, - $6, $7, $8, $9, $10, + $1, $2, $3, $4, $5, $6, + $7, $8, $9, $10, $11, $12 ) `, - tf.ID, tf.ProjectID, tf.SectionType, tf.Title, tf.Content, - tf.Version, string(tf.Status), uuid.Nil, nil, nil, + tf.ID, tf.ProjectID, tenantID, tf.SectionType, tf.Title, tf.Content, + string(tf.Status), "", nil, nil, tf.CreatedAt, tf.UpdatedAt, ) if err != nil { @@ -50,12 +60,11 @@ func (s *Store) CreateTechFileSection(ctx context.Context, projectID uuid.UUID, return tf, nil } -// UpdateTechFileSection updates the content of a tech file section and bumps version +// UpdateTechFileSection updates the content of a tech file section func (s *Store) UpdateTechFileSection(ctx context.Context, id uuid.UUID, content string) error { _, err := s.pool.Exec(ctx, ` UPDATE iace_tech_file_sections SET - content = $2, - version = version + 1, + html_content = $2, status = $3, updated_at = NOW() WHERE id = $1 @@ -69,19 +78,15 @@ func (s *Store) UpdateTechFileSection(ctx context.Context, id uuid.UUID, content // ApproveTechFileSection marks a tech file section as approved func (s *Store) ApproveTechFileSection(ctx context.Context, id uuid.UUID, approvedBy string) error { now := time.Now().UTC() - approvedByUUID, err := uuid.Parse(approvedBy) - if err != nil { - return fmt.Errorf("invalid approved_by UUID: %w", err) - } - _, err = s.pool.Exec(ctx, ` + _, err := s.pool.Exec(ctx, ` UPDATE iace_tech_file_sections SET status = $2, approved_by = $3, approved_at = $4, updated_at = $4 WHERE id = $1 - `, id, string(TechFileSectionStatusApproved), approvedByUUID, now) + `, id, string(TechFileSectionStatusApproved), approvedBy, now) if err != nil { return fmt.Errorf("approve tech file section: %w", err) } @@ -93,11 +98,13 @@ func (s *Store) ApproveTechFileSection(ctx context.Context, id uuid.UUID, approv func (s *Store) ListTechFileSections(ctx context.Context, projectID uuid.UUID) ([]TechFileSection, error) { rows, err := s.pool.Query(ctx, ` SELECT - id, project_id, section_type, title, content, - version, status, approved_by, approved_at, metadata, - created_at, updated_at + id, project_id, section_type, title, + COALESCE(html_content, '') AS content, status, + COALESCE(approved_by, '') AS approved_by, approved_at, + COALESCE(metadata, '{}'::jsonb) AS metadata, + created_at, COALESCE(updated_at, created_at) AS updated_at FROM iace_tech_file_sections WHERE project_id = $1 - ORDER BY section_type ASC, created_at ASC + ORDER BY created_at ASC `, projectID) if err != nil { return nil, fmt.Errorf("list tech file sections: %w", err) @@ -108,11 +115,13 @@ func (s *Store) ListTechFileSections(ctx context.Context, projectID uuid.UUID) ( for rows.Next() { var tf TechFileSection var status string + var approvedByStr string var metadata []byte err := rows.Scan( - &tf.ID, &tf.ProjectID, &tf.SectionType, &tf.Title, &tf.Content, - &tf.Version, &status, &tf.ApprovedBy, &tf.ApprovedAt, &metadata, + &tf.ID, &tf.ProjectID, &tf.SectionType, &tf.Title, + &tf.Content, &status, + &approvedByStr, &tf.ApprovedAt, &metadata, &tf.CreatedAt, &tf.UpdatedAt, ) if err != nil { @@ -120,6 +129,12 @@ func (s *Store) ListTechFileSections(ctx context.Context, projectID uuid.UUID) ( } tf.Status = TechFileSectionStatus(status) + tf.Version = 1 + if approvedByStr != "" { + if parsed, e := uuid.Parse(approvedByStr); e == nil { + tf.ApprovedBy = parsed + } + } json.Unmarshal(metadata, &tf.Metadata) sections = append(sections, tf)