package iace import ( "archive/zip" "bytes" "encoding/json" "fmt" "strings" "time" ) // ExportDOCX generates a minimal DOCX file containing the CE technical file sections func (e *DocumentExporter) ExportDOCX( project *Project, sections []TechFileSection, ) ([]byte, error) { if project == nil { return nil, fmt.Errorf("project must not be nil") } var buf bytes.Buffer zw := zip.NewWriter(&buf) contentTypes := ` ` if err := addZipEntry(zw, "[Content_Types].xml", contentTypes); err != nil { return nil, fmt.Errorf("failed to write [Content_Types].xml: %w", err) } rels := ` ` if err := addZipEntry(zw, "_rels/.rels", rels); err != nil { return nil, fmt.Errorf("failed to write _rels/.rels: %w", err) } docRels := ` ` if err := addZipEntry(zw, "word/_rels/document.xml.rels", docRels); err != nil { return nil, fmt.Errorf("failed to write word/_rels/document.xml.rels: %w", err) } docXML := e.buildDocumentXML(project, sections) if err := addZipEntry(zw, "word/document.xml", docXML); err != nil { return nil, fmt.Errorf("failed to write word/document.xml: %w", err) } if err := zw.Close(); err != nil { return nil, fmt.Errorf("failed to close ZIP: %w", err) } return buf.Bytes(), nil } func (e *DocumentExporter) buildDocumentXML(project *Project, sections []TechFileSection) string { var body strings.Builder body.WriteString(docxHeading(fmt.Sprintf("CE-Akte: %s", project.MachineName), 1)) metaLines := []string{ fmt.Sprintf("Hersteller: %s", project.Manufacturer), fmt.Sprintf("Maschinentyp: %s", project.MachineType), } if project.CEMarkingTarget != "" { metaLines = append(metaLines, fmt.Sprintf("CE-Kennzeichnungsziel: %s", project.CEMarkingTarget)) } metaLines = append(metaLines, fmt.Sprintf("Status: %s", project.Status), fmt.Sprintf("Datum: %s", time.Now().Format("02.01.2006")), ) for _, line := range metaLines { body.WriteString(docxParagraph(line, false)) } if project.Description != "" { body.WriteString(docxParagraph("", false)) body.WriteString(docxParagraph(project.Description, true)) } for _, section := range sections { body.WriteString(docxHeading(section.Title, 2)) body.WriteString(docxParagraph( fmt.Sprintf("Typ: %s | Status: %s | Version: %d", section.SectionType, string(section.Status), section.Version), true, )) if section.Content != "" { for _, line := range strings.Split(section.Content, "\n") { body.WriteString(docxParagraph(line, false)) } } else { body.WriteString(docxParagraph("(Kein Inhalt vorhanden)", true)) } } body.WriteString(docxParagraph("", false)) body.WriteString(docxParagraph( fmt.Sprintf("Generiert am %s mit BreakPilot AI Compliance SDK", time.Now().Format("02.01.2006 15:04")), true, )) return fmt.Sprintf(` %s `, body.String()) } // ExportJSON returns a JSON representation of the project export data func (e *DocumentExporter) ExportJSON( project *Project, sections []TechFileSection, hazards []Hazard, assessments []RiskAssessment, mitigations []Mitigation, classifications []RegulatoryClassification, ) ([]byte, error) { if project == nil { return nil, fmt.Errorf("project must not be nil") } payload := map[string]interface{}{ "project": project, "sections": sections, "hazards": hazards, "assessments": assessments, "mitigations": mitigations, "classifications": classifications, "exported_at": time.Now().UTC().Format(time.RFC3339), "format_version": "1.0", } data, err := json.MarshalIndent(payload, "", " ") if err != nil { return nil, fmt.Errorf("failed to marshal JSON: %w", err) } return data, nil }