From 3cec98d9d9b74577dfab1a17254ce41d69b69ee2dc63c48327b000796aa58ff8 Mon Sep 17 00:00:00 2001 From: tlg Date: Sun, 26 Apr 2026 13:29:31 +0200 Subject: [PATCH] S07: Teilgebiet 01 Iteration B (Iterationen B1, B1.5, B2) durchgezogen. Neue Datei build/build-reference-docx.py baut templates/reference.docx programmatisch aus Pandocs Default-Reference (Python-Stdlib only, kein pip; pandoc --print-default-data-file zur Laufzeit, ZIP entpacken, ElementTree-XML-Anpassungen, repacken). B1: Theme major+minor und alle direkten Schrift-Refs in styles.xml auf Calibri umgestellt (Code-Schriften wie Consolas bleiben), Tabellen-Default-Stil mit tblBorders=none auf allen Sides. B1.5: Body-DocDefault 11 pt, Heading 1/2/3 auf 15/13/12 pt analog PDF. B2: header1.xml (Default ab Seite 2 mit Name links und Lebenslauf rechts), header2.xml (leer fuer Seite 1 via titlePg), footer1.xml (rechts Seite n / m mit PAGE/NUMPAGES-Feldern, doppelt referenziert als default und first damit Seite 1 trotz titlePg den Footer hat). Page-Setup explizit in sectPr: A4 mit 2.2 cm oben/unten und 2.5 cm links/rechts analog PDF, Tab-Stop am rechten Textrand 9072 dxa. Beziehungen mit dynamisch naechster freier rId in document.xml.rels, Content-Types-Overrides in [Content_Types].xml, sectPr regex-ersetzt idempotent. Sandbox-End-to-End mit Pandoc 2.9 verifiziert (sectPr und Header/Footer im generierten DOCX vorhanden). Auf Thomas System: DOCX visuell bestaetigt. teilgebiete/01-lebenslauf.md um vollstaendigen Iteration-B-Block ergaenzt, Naechste-Schritte-Liste auf B3, B4, C, D umstrukturiert. agent-prompt.md Aktueller-Stand-Abschnitt fortgeschrieben mit Hinweisen zur reference-docx-Pipeline (manuell vor build.ps1 aufrufen, nicht von Hand in Word editieren) und zur Edit-Tool-Truncation auf dem NTFS-Mount. Build-UX-Fix in build.ps1 mit 3-Sekunden-Pause pro fehlgeschlagenem Schritt war ebenfalls Teil dieser Session. --- .checkpoint-pending.txt | 2 +- agent-prompt.md | 21 +- .../build/build-reference-docx.py | 401 ++++++++++++++++++ .../Lebenslauf_Dr-Ing_Thomas_Langer.docx | Bin 20589 -> 22550 bytes .../Lebenslauf_Dr-Ing_Thomas_Langer.pdf | 4 +- artefakte/01-lebenslauf/output/build.log | 6 +- .../01-lebenslauf/templates/reference.docx | Bin 10151 -> 12162 bytes changelog.md | 1 + teilgebiete/01-lebenslauf.md | 50 ++- 9 files changed, 464 insertions(+), 21 deletions(-) create mode 100644 artefakte/01-lebenslauf/build/build-reference-docx.py diff --git a/.checkpoint-pending.txt b/.checkpoint-pending.txt index 3f3076a..4fbff93 100644 --- a/.checkpoint-pending.txt +++ b/.checkpoint-pending.txt @@ -1,2 +1,2 @@ S07 -PDF-Build-Fehler endgueltig behoben. S06-Hotfix (array, calc, providecommand real) loeste das Problem nicht; nach Rebuild kam unveraendert "! LaTeX Error: No counter 'none' defined." Eigentliche Ursache: Pandoc 3.x emittiert fuer unnummerierte Tabellen direkt vor begin{longtable} die Zeile def LTcaptype none, ohne den Counter none zu definieren. Pandocs eigene Default-Vorlage definiert ihn (commit d835461 in Pandoc 3.8.2.1), Custom-Templates muessen das selbst tun (siehe Pandoc-Issue 11201). Fix: eine Zeile newcounter none direkt nach providecommand real im Tabellen-Block des Templates. Sandbox-Reproduktion exakter Fehlertext ohne Fix, sauberes PDF mit Fix. Auf Thomas' System: PDF wird erzeugt, Ausbildungs-Layout im PDF visuell bestaetigt. Iteration A fuer Teilgebiet 01 damit inhaltlich abgeschlossen. Build-UX-Fix: build.ps1 ergaenzt um Start-Sleep -Seconds 3 nach jedem fehlschlagenden Build-Schritt (Pflichtdatei-Check, PDF-Build, DOCX-Build), damit die rote Fehlerzeile lesbar bleibt bevor das PowerShell-Fenster zugeht. teilgebiete/01-lebenslauf.md um beide Fixes ergaenzt (zweistufige Hotfix-Geschichte, PDF-Bestaetigung, UX-Fix). agent-prompt.md Aktueller-Stand-Abschnitt fuer S08 fortgeschrieben mit verbleibender Iterationsreihenfolge B-C-D, Hinweise auf Pandoc-Versionsunterschied praeziser formuliert. +Teilgebiet 01 Iteration B (Iterationen B1, B1.5, B2) durchgezogen. Neue Datei build/build-reference-docx.py baut templates/reference.docx programmatisch aus Pandocs Default-Reference (Python-Stdlib only, kein pip; pandoc --print-default-data-file zur Laufzeit, ZIP entpacken, ElementTree-XML-Anpassungen, repacken). B1: Theme major+minor und alle direkten Schrift-Refs in styles.xml auf Calibri umgestellt (Code-Schriften wie Consolas bleiben), Tabellen-Default-Stil mit tblBorders=none auf allen Sides. B1.5: Body-DocDefault 11 pt, Heading 1/2/3 auf 15/13/12 pt analog PDF. B2: header1.xml (Default ab Seite 2 mit Name links und Lebenslauf rechts), header2.xml (leer fuer Seite 1 via titlePg), footer1.xml (rechts Seite n / m mit PAGE/NUMPAGES-Feldern, doppelt referenziert als default und first damit Seite 1 trotz titlePg den Footer hat). Page-Setup explizit in sectPr: A4 mit 2.2 cm oben/unten und 2.5 cm links/rechts analog PDF, Tab-Stop am rechten Textrand 9072 dxa. Beziehungen mit dynamisch naechster freier rId in document.xml.rels, Content-Types-Overrides in [Content_Types].xml, sectPr regex-ersetzt idempotent. Sandbox-End-to-End mit Pandoc 2.9 verifiziert (sectPr und Header/Footer im generierten DOCX vorhanden). Auf Thomas System: DOCX visuell bestaetigt. teilgebiete/01-lebenslauf.md um vollstaendigen Iteration-B-Block ergaenzt, Naechste-Schritte-Liste auf B3, B4, C, D umstrukturiert. agent-prompt.md Aktueller-Stand-Abschnitt fortgeschrieben mit Hinweisen zur reference-docx-Pipeline (manuell vor build.ps1 aufrufen, nicht von Hand in Word editieren) und zur Edit-Tool-Truncation auf dem NTFS-Mount. Build-UX-Fix in build.ps1 mit 3-Sekunden-Pause pro fehlgeschlagenem Schritt war ebenfalls Teil dieser Session. diff --git a/agent-prompt.md b/agent-prompt.md index 7079296..3307407 100644 --- a/agent-prompt.md +++ b/agent-prompt.md @@ -88,14 +88,19 @@ Setze zwischen sinnvollen Zwischenständen Checkpoints (z.B. nach "Marketing.md **Letzte Session:** S07 (2026-04-26) **Was wurde gemacht:** -- **PDF-Build-Fehler endgültig behoben.** Der S06-Hotfix (array, calc, providecommand real) hat das Problem nicht beseitigt — nach Rebuild auf Thomas' System kam unverändert `! LaTeX Error: No counter 'none' defined.` Eigentliche Ursache: Pandoc 3.x emittiert für unnummerierte Tabellen direkt vor `\begin{longtable}` die Zeile `\def\LTcaptype{none}`, ohne den Counter `none` zu definieren. Sobald longtable intern `\refstepcounter{\LTcaptype}` aufruft, bricht LaTeX ab. Pandocs eigene Default-Vorlage definiert den Counter (commit d835461 in 3.8.2.1), Custom-Templates müssen das selbst tun. Siehe [Pandoc-Issue #11201](https://github.com/jgm/pandoc/issues/11201). Fix: eine Zeile `\newcounter{none}` direkt nach `\providecommand{\real}` im Tabellen-Block des Templates. In der Sandbox sauber reproduziert (gleicher Fehlertext ohne Fix, sauberes PDF mit Fix). Auf Thomas' System: PDF wird erzeugt, Ausbildungs-Layout im PDF visuell bestätigt. -- **Iteration A für Teilgebiet 01 damit inhaltlich abgeschlossen** (Tabellen-Variante mit zwei Spalten ca. 14 % / 80 %, rahmenlos im PDF, native Word-Tabelle im DOCX — Rahmen-Aus folgt in Iteration B). -- **Build-UX-Fix:** `build/build.ps1` ergänzt um `Start-Sleep -Seconds 3` nach jedem fehlschlagenden Build-Schritt (Pflichtdatei-Check, PDF-Build, DOCX-Build). Vorher schloss sich das PowerShell-Fenster bei Doppelklick auf das Skript so schnell, dass die rote Fehlerzeile nicht lesbar war. Bei mehreren Fehlern in einem Lauf akkumulieren sich die Pausen — gewollt. +- **PDF-Build-Fehler endgültig behoben.** Pandoc-3.x-`\def\LTcaptype{none}`-Bug ([Issue #11201](https://github.com/jgm/pandoc/issues/11201)). Fix: `\newcounter{none}` im Template, sandbox-reproduziert. PDF läuft auf Thomas' System, Ausbildungs-Layout visuell bestätigt. **Iteration A damit inhaltlich abgeschlossen.** +- **Build-UX-Fix:** `build/build.ps1` mit `Start-Sleep -Seconds 3` pro fehlschlagendem Schritt, damit das PowerShell-Fenster bei Fehler nicht zu schnell schließt. +- **Iteration B durchgezogen — `reference.docx` programmatisch via `build/build-reference-docx.py` (Python-Stdlib only, kein pip).** Holt Pandoc-Default-Reference per `pandoc --print-default-data-file`, entpackt die DOCX als ZIP, modifiziert XML mit ElementTree, repackt. + - **B1 — Schriften:** Theme `majorFont` und `minorFont` beide auf Calibri (Pandoc 3.x setzt Defaults auf Aptos Display / Aptos). Defensive Maßnahme: alle direkten ``-Referenzen außerhalb von Code-Schriften (Consolas, Courier, ...) auf Calibri. + - **B1 — Tabellen:** Stil `Table` mit `` auf allen Sides. Word-Editor zeigt weiterhin Tabellen-Anzeige-Hilfslinien (kein Druck-Rendering); Druckansicht und PDF-Export sind sauber rahmenlos. + - **B1.5 — Schriftgrößen analog PDF:** DocDefault Body 11 pt, Heading 1/2/3 auf 15/13/12 pt. DOCX schrumpft von 10 auf 9 Seiten. + - **B2 — Header, Footer, Page-Setup:** `header1.xml` (Default ab Seite 2: Name links, „Lebenslauf" rechts), `header2.xml` (leer für Seite 1 via `titlePg`), `footer1.xml` (rechts „Seite n / m" mit `PAGE`/`NUMPAGES`-Feldern, einmal als `default`, einmal als `first` referenziert, damit Seite 1 trotz titlePg den Footer hat). Page-Setup explizit: A4 mit 2.2 cm oben/unten, 2.5 cm links/rechts (analog PDF). Tab-Stop am rechten Textrand 9072 dxa = 16 cm. Beziehungen werden mit dynamisch ermittelter nächster freier `rId` registriert; Content-Types-Overrides ergänzt; sectPr regex-basiert ersetzt (idempotent gegen `` und längere Varianten). Pandoc 2.9 und 3.x übernehmen die sectPr ins generierte DOCX (in der Sandbox end-to-end verifiziert). DOCX-Layout von Thomas visuell bestätigt: Seite 1 ohne Header und mit Footer, Seite 2 ff. Header und Footer wie gewünscht, Tab-Stops bündig am rechten Textrand. -**Nächste Aufgabe:** Teilgebiet 01 — drei verbleibende Iterationen in dieser Reihenfolge: -1. **B) `templates/reference.docx` in Word polieren** — Header/Footer setzen, Schriften auf Calibri vereinheitlichen, Listen-Schutz „Keep with next" und Widow-Control via Word-Stile, Tabellen-Stile so konfigurieren, dass die Ausbildungs-Tabelle ohne Rahmen rendert (Default-Tabellenstil oder benannter Stil). -2. **C) Foto-Einbindung** in cv.md mit Pandoc-Image-Syntax und Template-Anpassung für Position/Größe (z.B. oben rechts neben Name, ca. 3 cm). -3. **D) Hyphenation-Feintuning für PDF** — kurze Wortteile am Zeilenanfang mit höherer Penalty oder gezielten `\hyphenation`-Ausnahmen reduzieren. Iterativ. +**Nächste Aufgabe:** Teilgebiet 01 — verbleibende Iterationen: +1. **B3 — Keep with next + Widow/Orphan-Control für DOCX.** Schusterjungen-Schutz analog `\widowpenalty`/`needspace` im PDF. Auf Stilebene `` für Headings und `` als DocDefault. +2. **B4 (optional) — Heading-Farben auf DesTEngS-Blau und/oder Trennlinien analog PDF.** Eher Kosmetik bei Vorlage für Consulting-Agenturen. +3. **C — Foto-Einbindung** in cv.md mit Pandoc-Image-Syntax und Template-Anpassung für Position/Größe (z.B. oben rechts neben Name, ca. 3 cm). +4. **D — Hyphenation-Feintuning für PDF** — kurze Wortteile am Zeilenanfang mit höherer Penalty oder `\hyphenation`-Ausnahmen reduzieren. Nach D): Status von Teilgebiet 01 in `zentral-index.md` auf „abgeschlossen" setzen (R2-OK von Thomas). Anschließend nächstes Teilgebiet nach Priorität (laut Index Teilgebiet 02 „Zeugnis von ASMPT"). @@ -108,3 +113,5 @@ Nach D): Status von Teilgebiet 01 in `zentral-index.md` auf „abgeschlossen" se - **Sandbox kann nichts an `.git/` schreiben** (NTFS-Permission-Issue): Lock-Files, korrupte Index — alles muss von PowerShell aus repariert werden. - **`checkpoint.ps1` ist robust** gegen Anführungszeichen, Pipes, Whitespace-Anomalien und Index-Lock-Reste. `.checkpoint-pending.txt` darf ganz normal Sonderzeichen enthalten. - **`build.ps1` pausiert bei Fehler 3 Sekunden pro fehlgeschlagenem Schritt.** Nicht überrascht sein, wenn ein fehlerhafter Lauf entsprechend länger braucht. +- **`build/build-reference-docx.py` muss VOR `build.ps1` manuell aufgerufen werden, wenn `templates/reference.docx` neu gebaut werden soll.** Das Skript ist nicht in `build.ps1` integriert (würde jeden Build verlangsamen und Pandoc-Default-Reference jedes Mal neu ziehen). Wenn jemand die `reference.docx` von Hand in Word editiert, gehen die Änderungen beim nächsten Skript-Lauf verloren — Stile gehören also ins Skript, nicht in Word. +- **Edit-Tool kann Dateien beim Schreiben über den NTFS-Mount truncatieren** (mehrfach in S07 erlebt am Python-Skript). `mcp__workspace__bash` mit `cat <<'EOF' > path` ist die zuverlässige Alternative für längere Dateien (>~150 Zeilen). Nach jedem Edit auf NTFS-Mount-Datei: `wc -l` und `tail -c` zur Verifikation. diff --git a/artefakte/01-lebenslauf/build/build-reference-docx.py b/artefakte/01-lebenslauf/build/build-reference-docx.py new file mode 100644 index 0000000..b5d5c99 --- /dev/null +++ b/artefakte/01-lebenslauf/build/build-reference-docx.py @@ -0,0 +1,401 @@ +#!/usr/bin/env python3 +""" +build-reference-docx.py +======================= + +Baut die templates/reference.docx fuer die Pandoc-DOCX-Pipeline aus der +Pandoc-Default-Reference, mit gezielten Anpassungen. + +Iteration B1 + B1.5 + B2 (aktuell): + B1 - Theme-Schriften (majorFont und minorFont) beide auf Calibri. + B1 - Direkte Schriftnamen-Referenzen in styles.xml auf Calibri + (Code-Schriften wie Consolas bleiben). + B1 - Tabellen-Default-Stil "Table" mit tblBorders=none. + B1.5 - Body-DocDefault 11pt, Heading 1/2/3 auf 15/13/12 pt. + B2 - Header (Name links, "Lebenslauf" rechts) ab Seite 2; Seite 1 mit + leerem Header (titlePg-Mechanik). Footer (rechts: Seite n / m) auf + allen Seiten inkl. Seite 1 (footer-Ref fuer "first" zeigt auf den + gleichen Footer wie "default"). Page-Setup explizit: A4, Raender + analog PDF (top/bottom 2.2 cm, left/right 2.5 cm). Damit ist der + Tab-Stop deterministisch unabhaengig von Word-Locale-Defaults. + +Geplant in Folge-Iterationen: + B3 - Heading-Stile mit "keep with next", Widow/Orphan-Control auf Stilebene + B4 - optional Heading-Farben auf DesTEngS-Blau analog PDF + +Vorgehen: + 1. Pandoc-Default-Reference per `pandoc --print-default-data-file + reference.docx` extrahieren. + 2. Als ZIP entpacken. + 3. Relevante XML-Dateien anpassen, neue Header/Footer-XMLs anlegen, + Beziehungen und ContentTypes ergaenzen, sectPr setzen. + 4. Als neue ZIP-Datei (templates/reference.docx) speichern. + +Voraussetzungen: nur Python-Stdlib + Pandoc im PATH. +""" + +from __future__ import annotations + +import re +import subprocess +import sys +import tempfile +import zipfile +from pathlib import Path +from xml.etree import ElementTree as ET + +# --- Pfade ----------------------------------------------------------------- + +SCRIPT_DIR = Path(__file__).resolve().parent +BASE_DIR = SCRIPT_DIR.parent +TEMPLATES_DIR = BASE_DIR / "templates" +OUTPUT_FILE = TEMPLATES_DIR / "reference.docx" + +# --- XML-Namespaces -------------------------------------------------------- + +NS = { + "w": "http://schemas.openxmlformats.org/wordprocessingml/2006/main", + "a": "http://schemas.openxmlformats.org/drawingml/2006/main", + "r": "http://schemas.openxmlformats.org/officeDocument/2006/relationships", + "rel": "http://schemas.openxmlformats.org/package/2006/relationships", + "ct": "http://schemas.openxmlformats.org/package/2006/content-types", +} +for prefix, uri in NS.items(): + ET.register_namespace(prefix, uri) +ET.register_namespace("", NS["rel"]) + +W = "{%s}" % NS["w"] +A = "{%s}" % NS["a"] + +# --- Konfiguration --------------------------------------------------------- + +CODE_FONTS = {"consolas", "courier", "courier new", "liberation mono", + "monaco", "menlo", "fira mono", "fira code"} +TARGET_FONT = "Calibri" + +SIZE_BODY = 22 +SIZE_HEADING1 = 30 +SIZE_HEADING2 = 26 +SIZE_HEADING3 = 24 +HEADING_SIZES = {"Heading1": SIZE_HEADING1, + "Heading2": SIZE_HEADING2, + "Heading3": SIZE_HEADING3} + +# Page-Setup (in DXA, 1cm = 566.929 dxa; 1 inch = 1440 dxa) +# A4: 21.0 x 29.7 cm +PAGE_W = 11906 # A4 Breite +PAGE_H = 16838 # A4 Hoehe +MARGIN_TOP = 1247 # 2.2 cm +MARGIN_BOT = 1247 # 2.2 cm +MARGIN_LEFT = 1417 # 2.5 cm +MARGIN_RIGHT = 1417 # 2.5 cm +HEADER_POS = 720 # 1.27 cm vom oberen Seitenrand +FOOTER_POS = 720 # 1.27 cm vom unteren Seitenrand +# Tab-Stop am rechten Textrand: PAGE_W - LEFT - RIGHT = 9072 dxa = 16 cm +HEADER_RIGHT_TAB = PAGE_W - MARGIN_LEFT - MARGIN_RIGHT + +HEADER_LEFT = "Dr.-Ing. Thomas Langer" +HEADER_RIGHT = "Lebenslauf" + +# --- Hilfsfunktionen ------------------------------------------------------- + +def log(msg: str) -> None: + print(f"[build-reference-docx] {msg}", flush=True) + +XML_DECL = b'\n' + +def write_xml(tree: ET.ElementTree, dest: Path) -> None: + body = ET.tostring(tree.getroot(), encoding="utf-8") + dest.write_bytes(XML_DECL + body) + +def write_xml_bytes(content: bytes, dest: Path) -> None: + dest.write_bytes(XML_DECL + content) + +def fetch_pandoc_default(dest: Path) -> None: + log("Pandoc-Default-Reference extrahieren ...") + result = subprocess.run( + ["pandoc", "--print-default-data-file", "reference.docx"], + capture_output=True, check=False, + ) + if result.returncode != 0: + sys.stderr.write(result.stderr.decode("utf-8", errors="replace")) + raise SystemExit(f"pandoc liefert Exit-Code {result.returncode}") + dest.write_bytes(result.stdout) + log(f" -> {dest} ({dest.stat().st_size} Bytes)") + +def unpack_docx(src: Path, dest_dir: Path) -> None: + with zipfile.ZipFile(src, "r") as z: + z.extractall(dest_dir) + +def repack_docx(src_dir: Path, dest: Path) -> None: + files = [] + for path in src_dir.rglob("*"): + if path.is_file(): + arcname = path.relative_to(src_dir).as_posix() + files.append((path, arcname)) + files.sort(key=lambda t: (0 if t[1] == "[Content_Types].xml" else 1, t[1])) + with zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED) as z: + for path, arcname in files: + z.write(path, arcname) + +def is_code_font(name: str) -> bool: + return (name or "").strip().lower() in CODE_FONTS + +# --- B1: Schriften --------------------------------------------------------- + +def set_theme_fonts_to_calibri(theme_xml: Path) -> None: + tree = ET.parse(theme_xml) + root = tree.getroot() + for kind in ("majorFont", "minorFont"): + font = root.find(f".//{A}{kind}") + if font is None: + raise RuntimeError(f"{kind}-Element nicht im Theme") + latin = font.find(f"{A}latin") + if latin is None: + raise RuntimeError(f"{kind}/latin-Element nicht gefunden") + old = latin.get("typeface") + latin.set("typeface", TARGET_FONT) + log(f" Theme {kind}/latin: {old!r} -> {TARGET_FONT!r}") + write_xml(tree, theme_xml) + +def replace_direct_fonts_in_styles(styles_xml: Path) -> None: + tree = ET.parse(styles_xml) + root = tree.getroot() + changed = 0 + skipped = 0 + for rfonts in root.iter(f"{W}rFonts"): + for attr in (f"{W}ascii", f"{W}hAnsi", f"{W}cs", f"{W}eastAsia"): + val = rfonts.get(attr) + if val is None: + continue + if is_code_font(val): + skipped += 1 + continue + if val != TARGET_FONT: + rfonts.set(attr, TARGET_FONT) + changed += 1 + log(f" styles.xml: {changed} direkte Font-Attribute auf {TARGET_FONT!r}" + f" gesetzt (Code-Fonts unangetastet: {skipped})") + write_xml(tree, styles_xml) + +# --- B1: Tabellen ---------------------------------------------------------- + +def set_table_borders_none(styles_xml: Path) -> None: + tree = ET.parse(styles_xml) + root = tree.getroot() + style = next((s for s in root.findall(f"{W}style") + if s.get(f"{W}styleId") == "Table"), None) + if style is None: + raise RuntimeError("Style 'Table' nicht in styles.xml") + tbl_pr = style.find(f"{W}tblPr") or ET.SubElement(style, f"{W}tblPr") + existing = tbl_pr.find(f"{W}tblBorders") + if existing is not None: + tbl_pr.remove(existing) + borders = ET.SubElement(tbl_pr, f"{W}tblBorders") + for side in ("top", "left", "bottom", "right", "insideH", "insideV"): + e = ET.SubElement(borders, f"{W}{side}") + e.set(f"{W}val", "none") + e.set(f"{W}sz", "0") + e.set(f"{W}space", "0") + e.set(f"{W}color", "auto") + log(" Style 'Table': tblBorders=none auf allen Sides") + write_xml(tree, styles_xml) + +# --- B1.5: Schriftgroessen ------------------------------------------------ + +def set_default_body_size(styles_xml: Path) -> None: + tree = ET.parse(styles_xml) + root = tree.getroot() + docDefaults = root.find(f"{W}docDefaults") or ET.SubElement(root, f"{W}docDefaults") + rPrDefault = docDefaults.find(f"{W}rPrDefault") or ET.SubElement(docDefaults, f"{W}rPrDefault") + rPr = rPrDefault.find(f"{W}rPr") or ET.SubElement(rPrDefault, f"{W}rPr") + for tag in (f"{W}sz", f"{W}szCs"): + elem = rPr.find(tag) or ET.SubElement(rPr, tag) + elem.set(f"{W}val", str(SIZE_BODY)) + log(f" DocDefault Body-Schriftgroesse: {SIZE_BODY/2} pt") + write_xml(tree, styles_xml) + +def set_heading_sizes(styles_xml: Path) -> None: + tree = ET.parse(styles_xml) + root = tree.getroot() + for style in root.findall(f"{W}style"): + sid = style.get(f"{W}styleId") + if sid not in HEADING_SIZES: + continue + target = HEADING_SIZES[sid] + rPr = style.find(f"{W}rPr") or ET.SubElement(style, f"{W}rPr") + for tag in (f"{W}sz", f"{W}szCs"): + elem = rPr.find(tag) or ET.SubElement(rPr, tag) + elem.set(f"{W}val", str(target)) + log(f" Stil {sid!r}: Schriftgroesse {target/2} pt") + write_xml(tree, styles_xml) + +# --- B2: Header und Footer ------------------------------------------------ + +def header_default_xml() -> bytes: + return ( + b'\n' + b' \n' + b' \n' + b' \n' + b' \n' + b' \n' + b' \n' + b' ' + HEADER_LEFT.encode() + b'\n' + b' ' + HEADER_RIGHT.encode() + b'\n' + b' \n' + b'\n' + ) + +def header_first_blank_xml() -> bytes: + return ( + b'\n' + b' \n' + b'\n' + ) + +def footer_default_xml() -> bytes: + return ( + b'\n' + b' \n' + b' \n' + b' \n' + b' \n' + b' \n' + b' \n' + b' Seite \n' + b' \n' + b' 1\n' + b' \n' + b' / \n' + b' \n' + b' 1\n' + b' \n' + b' \n' + b'\n' + ) + +REL_HEADER = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/header" +REL_FOOTER = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer" +CT_HEADER = "application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml" +CT_FOOTER = "application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml" + +def next_free_rel_id(rels_xml: Path) -> int: + text = rels_xml.read_text(encoding="utf-8") + ids = [int(m.group(1)) for m in re.finditer(r'Id="rId(\d+)"', text)] + return (max(ids) + 1) if ids else 1 + +def add_relationship(rels_xml: Path, rid: str, rtype: str, target: str) -> None: + text = rels_xml.read_text(encoding="utf-8") + new_rel = f'' + if new_rel in text: + return + text = text.replace("", new_rel + "") + rels_xml.write_text(text, encoding="utf-8") + +def add_content_type_override(ct_xml: Path, part_name: str, ct: str) -> None: + text = ct_xml.read_text(encoding="utf-8") + new_override = f'' + if part_name in text: + return + text = text.replace("", new_override + "") + ct_xml.write_text(text, encoding="utf-8") + +def update_sectpr_with_headers(document_xml: Path, + header_default_rid: str, + header_first_rid: str, + footer_default_rid: str) -> None: + """Ersetzt sectPr durch Page-Setup + Header/Footer-Refs + titlePg. + Footer-Ref wird zweimal eingebaut (default und first), beide auf + den gleichen Footer — dann hat Seite 1 trotz titlePg den Footer.""" + text = document_xml.read_text(encoding="utf-8") + new_sectpr = ( + f'' + f'' + f'' + f'' + f'' + f'' + f'' + f'' + f'' + ) + new_text, n = re.subn( + r'|.*?', + new_sectpr, text, flags=re.DOTALL, + ) + if n == 0: + new_text = text.replace("", new_sectpr + "") + document_xml.write_text(new_text, encoding="utf-8") + log(f" document.xml sectPr: pgSz/pgMar (A4, 2.2/2.5cm Raender), Header" + f" default+first, Footer default+first auf gleicher rId, titlePg") + +def add_header_footer(unpacked: Path) -> None: + word_dir = unpacked / "word" + rels_xml = word_dir / "_rels" / "document.xml.rels" + ct_xml = unpacked / "[Content_Types].xml" + doc_xml = word_dir / "document.xml" + + write_xml_bytes(header_default_xml(), word_dir / "header1.xml") + write_xml_bytes(header_first_blank_xml(), word_dir / "header2.xml") + write_xml_bytes(footer_default_xml(), word_dir / "footer1.xml") + log(" word/header1.xml (default), header2.xml (first blank)," + " footer1.xml geschrieben") + + next_id = next_free_rel_id(rels_xml) + rid_h_def, rid_h_first, rid_f_def = (f"rId{next_id+i}" for i in range(3)) + add_relationship(rels_xml, rid_h_def, REL_HEADER, "header1.xml") + add_relationship(rels_xml, rid_h_first, REL_HEADER, "header2.xml") + add_relationship(rels_xml, rid_f_def, REL_FOOTER, "footer1.xml") + log(f" Beziehungen: {rid_h_def}=header1, {rid_h_first}=header2," + f" {rid_f_def}=footer1") + + add_content_type_override(ct_xml, "/word/header1.xml", CT_HEADER) + add_content_type_override(ct_xml, "/word/header2.xml", CT_HEADER) + add_content_type_override(ct_xml, "/word/footer1.xml", CT_FOOTER) + log(" [Content_Types].xml: Override-Eintraege fuer header1/2 und footer1") + + update_sectpr_with_headers(doc_xml, rid_h_def, rid_h_first, rid_f_def) + +# --- Hauptablauf ----------------------------------------------------------- + +def main() -> int: + log(f"Ziel: {OUTPUT_FILE}") + TEMPLATES_DIR.mkdir(parents=True, exist_ok=True) + + with tempfile.TemporaryDirectory(prefix="refdocx-") as tmp: + tmp_dir = Path(tmp) + default_docx = tmp_dir / "pandoc-default.docx" + unpacked = tmp_dir / "unpacked" + + fetch_pandoc_default(default_docx) + unpacked.mkdir() + unpack_docx(default_docx, unpacked) + + theme_xml = unpacked / "word" / "theme" / "theme1.xml" + styles_xml = unpacked / "word" / "styles.xml" + + log("Anpassung: Theme major+minor auf Calibri") + set_theme_fonts_to_calibri(theme_xml) + log("Anpassung: Direkte Font-Referenzen in styles.xml -> Calibri") + replace_direct_fonts_in_styles(styles_xml) + log("Anpassung: Tabellen-Default ohne Rahmen") + set_table_borders_none(styles_xml) + log("Anpassung: Body-Schriftgroesse 11 pt (DocDefault)") + set_default_body_size(styles_xml) + log("Anpassung: Heading-Schriftgroessen 15/13/12 pt") + set_heading_sizes(styles_xml) + log("Anpassung: Header und Footer einbauen (B2)") + add_header_footer(unpacked) + + log("Repack als reference.docx") + repack_docx(unpacked, OUTPUT_FILE) + log(f" -> {OUTPUT_FILE} ({OUTPUT_FILE.stat().st_size} Bytes)") + + log("Fertig.") + return 0 + +if __name__ == "__main__": + sys.exit(main()) diff --git a/artefakte/01-lebenslauf/output/Lebenslauf_Dr-Ing_Thomas_Langer.docx b/artefakte/01-lebenslauf/output/Lebenslauf_Dr-Ing_Thomas_Langer.docx index 5b1df74b50fc57c54f032f68422d56aab84678f226b7b6567912dbba7fab83db..09bc7589f1251401c22dd5cfa7a96b6d5a8dfea0b62bbc9084db93ff1e55b319 100644 GIT binary patch delta 19811 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%0De$0;?_ zLAy%{0b%m*@d5u8A}&tfIN8lY|0@8TSjz#N^eK8*Hc${#y*xe;D)S3+Jdf}53qZRI zAo|#{^Ke$czmn&}_d_}VmxkRIy?Ew7r0ibhi443q`GNa0+PAltHuWtqJ#J7y==>se zcjIkSZNyOfc>94aJpok@Zg&lw@o8>dz|q~!4XBy*KloIe-TQJo@gOaHgR$5zQwRk} z#@q+KqX3Owg=_n`uKf^p^q0)`*3@1-#C7o6Fac@4EkEztdf57X{ByyoV2mC<2*$rl zcx#0WERY!(4*w$wyjKPDf${Y);a$SJX9U~QRl!zJV16LDOL*_-@sD^_urmy=4Hv{R zGVRoQZ>ruFKL`JB;--6QCwgxp+eTkD*@ga<)_$R3J507WrEJ4lO?L#!R)T>Wu>k+K RpnHp#p^=$^LG?2I)886Q*uVe) delta 17709 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 endobj 162 0 obj -<< /Author(\376\377\000D\000r\000.\000-\000I\000n\000g\000.\000\040\000T\000h\000o\000m\000a\000s\000\040\000L\000a\000n\000g\000e\000r)/Title(\376\377\000L\000e\000b\000e\000n\000s\000l\000a\000u\000f\000\040\000D\000r\000.\000-\000I\000n\000g\000.\000\040\000T\000h\000o\000m\000a\000s\000\040\000L\000a\000n\000g\000e\000r)/Subject()/Creator(\376\377\000P\000a\000n\000d\000o\000c\000\040\000+\000\040\000L\000u\000a\000L\000a\000T\000e\000X)/Keywords() /Producer (LuaTeX-1.24.0) /CreationDate (D:20260426104140+02'00') /ModDate (D:20260426104140+02'00') /Trapped /False /PTEX.FullBanner (This is LuaHBTeX, Version 1.24.0 (MiKTeX 26.2)) >> +<< /Author(\376\377\000D\000r\000.\000-\000I\000n\000g\000.\000\040\000T\000h\000o\000m\000a\000s\000\040\000L\000a\000n\000g\000e\000r)/Title(\376\377\000L\000e\000b\000e\000n\000s\000l\000a\000u\000f\000\040\000D\000r\000.\000-\000I\000n\000g\000.\000\040\000T\000h\000o\000m\000a\000s\000\040\000L\000a\000n\000g\000e\000r)/Subject()/Creator(\376\377\000P\000a\000n\000d\000o\000c\000\040\000+\000\040\000L\000u\000a\000L\000a\000T\000e\000X)/Keywords() /Producer (LuaTeX-1.24.0) /CreationDate (D:20260426132419+02'00') /ModDate (D:20260426132419+02'00') /Trapped /False /PTEX.FullBanner (This is LuaHBTeX, Version 1.24.0 (MiKTeX 26.2)) >> endobj xref 0 163 @@ -895,7 +895,7 @@ xref 0000065582 00000 n 0000065708 00000 n trailer -<< /Size 163 /Root 161 0 R /Info 162 0 R /ID [ <53CF6B4AF812DB9CEA60519E77C224DA> <53CF6B4AF812DB9CEA60519E77C224DA> ] >> +<< /Size 163 /Root 161 0 R /Info 162 0 R /ID [ ] >> startxref 66368 %%EOF diff --git a/artefakte/01-lebenslauf/output/build.log b/artefakte/01-lebenslauf/output/build.log index 678c02d..03e1de2 100644 --- a/artefakte/01-lebenslauf/output/build.log +++ b/artefakte/01-lebenslauf/output/build.log @@ -1,4 +1,4 @@ -===== Build gestartet: 2026-04-26 10:41:37 ===== +===== Build gestartet: 2026-04-26 13:24:16 ===== Source: Q:\DesTEngS\Pro\Git\marketing\claude_cowork\artefakte\01-lebenslauf\source\cv.md Template-TEX: Q:\DesTEngS\Pro\Git\marketing\claude_cowork\artefakte\01-lebenslauf\templates\template.tex Reference: Q:\DesTEngS\Pro\Git\marketing\claude_cowork\artefakte\01-lebenslauf\templates\reference.docx @@ -9,5 +9,5 @@ Cmd: pandoc --from=markdown+smart --pdf-engine=lualatex --template=Q:\DesTEngS\P PDF OK: Q:\DesTEngS\Pro\Git\marketing\claude_cowork\artefakte\01-lebenslauf\output\Lebenslauf_Dr-Ing_Thomas_Langer.pdf (68.2 KB) --- Pandoc -> DOCX --- Cmd: pandoc --from=markdown+smart --reference-doc=Q:\DesTEngS\Pro\Git\marketing\claude_cowork\artefakte\01-lebenslauf\templates\reference.docx --resource-path=Q:\DesTEngS\Pro\Git\marketing\claude_cowork\artefakte\01-lebenslauf\source --output=Q:\DesTEngS\Pro\Git\marketing\claude_cowork\artefakte\01-lebenslauf\output\Lebenslauf_Dr-Ing_Thomas_Langer.docx Q:\DesTEngS\Pro\Git\marketing\claude_cowork\artefakte\01-lebenslauf\source\cv.md -DOCX OK: Q:\DesTEngS\Pro\Git\marketing\claude_cowork\artefakte\01-lebenslauf\output\Lebenslauf_Dr-Ing_Thomas_Langer.docx (20.1 KB) -===== Build beendet: 2026-04-26 10:41:42, Exit-Code 0 ===== +DOCX OK: Q:\DesTEngS\Pro\Git\marketing\claude_cowork\artefakte\01-lebenslauf\output\Lebenslauf_Dr-Ing_Thomas_Langer.docx (22 KB) +===== Build beendet: 2026-04-26 13:24:21, Exit-Code 0 ===== diff --git a/artefakte/01-lebenslauf/templates/reference.docx b/artefakte/01-lebenslauf/templates/reference.docx index 93cbc5414b02352b253d261b1ce5f3dae223e683d3aed30e35ae9d8a124f5f24..2ca9064b92d69b81f195579f5c53bd551a21241a4cbebaa5b1845cfbe1d23483 100644 GIT binary patch literal 12162 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

>777W7U6c9K9G`r03Es_ART| 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 M=Uo#__Velg05H3{AOHXW diff --git a/changelog.md b/changelog.md index edfa767..70fcb6d 100644 --- a/changelog.md +++ b/changelog.md @@ -43,3 +43,4 @@ Chronologisches Log aller Entscheidungen und Prozessereignisse. 2026-04-25 22:35 | S06 | Tooling-Fix: checkpoint.ps1 robust gegen problematische Eingabedaten gemacht. Commit-Message wird jetzt via Temp-Datei und git commit -F uebergeben statt via -m mit String, damit doppelte Anfuehrungszeichen im Summary nicht mehr das Argument zerlegen (Ursache des fehlgeschlagenen Hotfix-Commits zuvor). Pipe-Zeichen im Summary werden vorab abgelehnt, da sie mit dem Changelog-Format Timestamp Pipe Session Pipe Summary kollidieren. Whitespace und Zeilenumbrueche im Summary werden zu einem einzelnen Leerzeichen normalisiert. Pre-flight-Checks ergaenzt: Existenz von .git, verwaiste .git/index.lock mit klarer Anleitung melden, changelog.md muss vor dem Lauf clean sein. Atomarer Rollback bei Fehler im Hauptablauf: changelog.md wird auf Original-Stand zurueckgeschrieben und Index-Stagung von changelog.md per git restore --staged oder git reset HEAD zurueckgesetzt, sodass der naechste Lauf nicht doppelt anhaengt. Cleanup-Robustheit: Temp-Message-Datei wird in finally geloescht, das Loeschen der Pending-Datei ist nicht mehr fatal sondern nur eine Warnung. 2026-04-25 22:43 | S06 | Session-Abschluss S06. Teilgebiet 01 Iteration A inhaltlich umgesetzt: Ausbildung als 2-Spalten-Layout via Pandoc-Multiline-Tabelle ohne Header, Template um array, calc, booktabs, longtable und providecommand real ergänzt, alle Linienbreiten auf 0pt. DOCX-Layout von Thomas visuell bestätigt (nur Default-Tabellenrahmen offen, Rahmen-Aus in Iteration B). PDF-Build mit Hotfix steht noch aus — erste Aufgabe der nächsten Session ist build.ps1 laufen lassen und das Ausbildungs-Layout im PDF prüfen. Tooling-Fix in checkpoint.ps1 abgeschlossen (Quoting-Bug, Pipe-Validierung, Whitespace-Normalisierung, Pre-flight-Checks, atomarer Rollback bei Fehler). agent-prompt.md Aktueller-Stand-Abschnitt für S07 fortgeschrieben mit verbleibender Iterationsreihenfolge B-C-D, neuen Lehren aus S06 dokumentiert (Sandbox-Reads über NTFS-Mount können stale sein, Sandbox-Pandoc 2.9 vs Thomas' Pandoc 3.x Output-Unterschiede). 2026-04-26 10:58 | S07 | PDF-Build-Fehler endgueltig behoben. S06-Hotfix (array, calc, providecommand real) loeste das Problem nicht; nach Rebuild kam unveraendert "! LaTeX Error: No counter 'none' defined." Eigentliche Ursache: Pandoc 3.x emittiert fuer unnummerierte Tabellen direkt vor begin{longtable} die Zeile def LTcaptype none, ohne den Counter none zu definieren. Pandocs eigene Default-Vorlage definiert ihn (commit d835461 in Pandoc 3.8.2.1), Custom-Templates muessen das selbst tun (siehe Pandoc-Issue 11201). Fix: eine Zeile newcounter none direkt nach providecommand real im Tabellen-Block des Templates. Sandbox-Reproduktion exakter Fehlertext ohne Fix, sauberes PDF mit Fix. Auf Thomas' System: PDF wird erzeugt, Ausbildungs-Layout im PDF visuell bestaetigt. Iteration A fuer Teilgebiet 01 damit inhaltlich abgeschlossen. Build-UX-Fix: build.ps1 ergaenzt um Start-Sleep -Seconds 3 nach jedem fehlschlagenden Build-Schritt (Pflichtdatei-Check, PDF-Build, DOCX-Build), damit die rote Fehlerzeile lesbar bleibt bevor das PowerShell-Fenster zugeht. teilgebiete/01-lebenslauf.md um beide Fixes ergaenzt (zweistufige Hotfix-Geschichte, PDF-Bestaetigung, UX-Fix). agent-prompt.md Aktueller-Stand-Abschnitt fuer S08 fortgeschrieben mit verbleibender Iterationsreihenfolge B-C-D, Hinweise auf Pandoc-Versionsunterschied praeziser formuliert. +2026-04-26 13:29 | S07 | Teilgebiet 01 Iteration B (Iterationen B1, B1.5, B2) durchgezogen. Neue Datei build/build-reference-docx.py baut templates/reference.docx programmatisch aus Pandocs Default-Reference (Python-Stdlib only, kein pip; pandoc --print-default-data-file zur Laufzeit, ZIP entpacken, ElementTree-XML-Anpassungen, repacken). B1: Theme major+minor und alle direkten Schrift-Refs in styles.xml auf Calibri umgestellt (Code-Schriften wie Consolas bleiben), Tabellen-Default-Stil mit tblBorders=none auf allen Sides. B1.5: Body-DocDefault 11 pt, Heading 1/2/3 auf 15/13/12 pt analog PDF. B2: header1.xml (Default ab Seite 2 mit Name links und Lebenslauf rechts), header2.xml (leer fuer Seite 1 via titlePg), footer1.xml (rechts Seite n / m mit PAGE/NUMPAGES-Feldern, doppelt referenziert als default und first damit Seite 1 trotz titlePg den Footer hat). Page-Setup explizit in sectPr: A4 mit 2.2 cm oben/unten und 2.5 cm links/rechts analog PDF, Tab-Stop am rechten Textrand 9072 dxa. Beziehungen mit dynamisch naechster freier rId in document.xml.rels, Content-Types-Overrides in [Content_Types].xml, sectPr regex-ersetzt idempotent. Sandbox-End-to-End mit Pandoc 2.9 verifiziert (sectPr und Header/Footer im generierten DOCX vorhanden). Auf Thomas System: DOCX visuell bestaetigt. teilgebiete/01-lebenslauf.md um vollstaendigen Iteration-B-Block ergaenzt, Naechste-Schritte-Liste auf B3, B4, C, D umstrukturiert. agent-prompt.md Aktueller-Stand-Abschnitt fortgeschrieben mit Hinweisen zur reference-docx-Pipeline (manuell vor build.ps1 aufrufen, nicht von Hand in Word editieren) und zur Edit-Tool-Truncation auf dem NTFS-Mount. Build-UX-Fix in build.ps1 mit 3-Sekunden-Pause pro fehlgeschlagenem Schritt war ebenfalls Teil dieser Session. diff --git a/teilgebiete/01-lebenslauf.md b/teilgebiete/01-lebenslauf.md index 767d51d..3d0b73f 100644 --- a/teilgebiete/01-lebenslauf.md +++ b/teilgebiete/01-lebenslauf.md @@ -140,12 +140,45 @@ Die in S04 mit docx-js erstellte Version hatte strukturelle typographische Mäng **Build-UX-Fix (S07):** `build/build.ps1` ergänzt um `Start-Sleep -Seconds 3` nach jedem fehlschlagenden Build-Schritt (Pflichtdatei-Check, PDF, DOCX). Bei Doppelklick auf `checkpoint.cmd`-artigen Aufruf schließt sich das PowerShell-Fenster sonst sofort und Fehlermeldungen sind nicht lesbar. Bei mehreren Fehlern in einem Lauf akkumulieren sich die Pausen — gewollt. +## Iteration B (S07) — `reference.docx` programmatisch bauen + +**Ansatz:** Anstatt die `reference.docx` manuell in Word zu pflegen (nicht versionierbar, nicht reproduzierbar), wird sie durch ein Python-Skript `build/build-reference-docx.py` aus Pandocs Default-Reference erzeugt und gezielt angepasst. Nur Python-Stdlib (`zipfile`, `xml.etree.ElementTree`, `subprocess`, `re`) — keine pip-Abhängigkeit. Das Skript läuft unter Sandbox-Pandoc 2.9 und Thomas' Pandoc 3.x gleichermaßen, weil es die Pandoc-Default-Reference per `pandoc --print-default-data-file reference.docx` zur Laufzeit zieht. Manueller Aufruf vor jedem `build.ps1`, wenn Stile geändert wurden. + +**B1 — Schriften und Tabellen:** + +- Theme-Schriften `majorFont` und `minorFont` beide auf `Calibri` umgestellt (Pandoc 3.x setzt sie als Default auf `Aptos Display` und `Aptos`, Sandbox-Pandoc 2.9 auf `Calibri` und `Cambria`). +- Defensive Maßnahme: alle direkten Schriftnamen-Referenzen in `styles.xml` (z.B. ``) auf Calibri umgestellt, ausgenommen Code-Schriften (Consolas, Courier, ...). In der Pandoc-3.x-Variante kommt das mit 0 Treffern aus, in zukünftigen Pandoc-Versionen mit direkten Heading-Schriftreferenzen würde es greifen. +- Tabellen-Default-Stil `Table` bekommt explizite `` mit `val="none"` auf allen Sides (`top`, `left`, `bottom`, `right`, `insideH`, `insideV`). Word-Editor zeigt die Default-„Tabellenbegrenzungen" weiterhin als Anzeige-Hilfe an (kein Druck-Rendering), Druckansicht und PDF-Export sind sauber rahmenlos. + +**B1.5 — Schriftgrößen analog PDF:** + +- DocDefault `` auf 22 (= 11 pt Body, analog `template.tex`). +- Heading 1/2/3 explizit auf 30/26/24 (= 15/13/12 pt). Damit ist die Heading-Hierarchie visuell ähnlich zum PDF, ohne den Word-Default-Sprung von 20 pt nach 12 pt. +- Effekt: DOCX schrumpft von 10 auf 9 Seiten (im PDF sind es 7). + +**B2 — Header, Footer, Page-Setup:** + +- `word/header1.xml` (Default ab Seite 2): links „Dr.-Ing. Thomas Langer", rechts „Lebenslauf" (Tab-Stop am rechten Textrand). +- `word/header2.xml` (erste Seite): leerer `` über `` aktiviert. +- `word/footer1.xml`: rechtsbündig „Seite n / m" mit Word-Feldern `PAGE` und `NUMPAGES`. Wird über zwei `footerReference`-Einträge (`type="default"` und `type="first"`) auf alle Seiten inkl. Seite 1 angewendet — ohne den `type="first"`-Eintrag würde `titlePg` Seite 1 ohne Footer lassen. +- Page-Setup explizit in ``: A4 (`pgSz w:w="11906" w:h="16838"`), Ränder 2.2 cm oben/unten, 2.5 cm links/rechts (analog PDF). Damit ist der Tab-Stop an `9072 dxa` (= 16 cm Textbreite) deterministisch unabhängig von Word-Locale-Defaults; ohne explizites Page-Setup waren die Tab-Stops vorher etwa 5 mm zu weit links. +- Beziehungen werden in `word/_rels/document.xml.rels` mit dynamisch ermittelter nächster freier `rId` registriert; Content-Types-Overrides in `[Content_Types].xml` ergänzt; `` in `word/document.xml` regex-basiert ersetzt (idempotent gegenüber Pandoc-Defaults `` und längeren Varianten). Pandoc übernimmt die letzte sectPr aus der reference.docx ins generierte DOCX — End-to-End-Test in der Sandbox bestätigt: alle Header/Footer-Refs, pgMar und titlePg sind im finalen DOCX vorhanden. + +**Visuelle Bestätigung im Word (S07):** + +- Body: Calibri 11 pt; Headings 1/2/3: Calibri 15/13/12 pt. +- Ausbildungs-Tabelle in Druckansicht und PDF-Export rahmenlos. +- Seite 1 ohne Header, mit Footer. +- Seite 2 ff. mit Header (Name links, „Lebenslauf" rechts) und Footer (Seite n / m). +- Tab-Stops „Lebenslauf" und Seitenzahl bündig am rechten Textrand. + ## Nächste Schritte -1. **Iteration B — `templates/reference.docx` in Word polieren:** Header/Footer setzen, Schriften auf Calibri vereinheitlichen, Listen-Schutz „Keep with next" und Widow-Control via Word-Stile, Stile `DefinitionTerm` und `Definition` für 2-Spalten-Verhalten konfigurieren (z.B. fester linker Einzug auf `Definition`, hängende Einrückung). -2. **Iteration C — Foto-Einbindung:** Portraitfoto in `source/cv.md` einbetten (Pandoc-Image-Syntax), Position und Größe im Template absichern (z.B. oben rechts neben Name, ca. 3 cm). -3. **Iteration D — Hyphenation-Feintuning für PDF:** Kurze Wortteile am Zeilenanfang mit höherer Penalty oder gezielten `\hyphenation`-Ausnahmen reduzieren. Iterativ. -4. Teilgebiet nach erfolgreichem Output und Freigabe durch Thomas abschließen (R2-OK von Thomas: Status auf „abgeschlossen" im zentral-index.md). +1. **Iteration B3 — Heading-Stile mit „keep with next" und Widow/Orphan-Control:** Schusterjungen-Schutz für DOCX analog zu `\widowpenalty`/`needspace` im PDF. Auf Stilebene über `` für Headings und `` als DocDefault. +2. **Iteration B4 (optional)** — Heading-Farben auf DesTEngS-Blau und/oder Trennlinien analog PDF, falls das DOCX optisch näher ans PDF heran soll. Bei Vorlage für Consulting-Agenturen, die das Layout ohnehin überschreiben, ist das aber eher Kosmetik. +3. **Iteration C — Foto-Einbindung:** Portraitfoto in `source/cv.md` einbetten (Pandoc-Image-Syntax), Position und Größe im Template absichern (z.B. oben rechts neben Name, ca. 3 cm). +4. **Iteration D — Hyphenation-Feintuning für PDF:** Kurze Wortteile am Zeilenanfang mit höherer Penalty oder gezielten `\hyphenation`-Ausnahmen reduzieren. Iterativ. +5. Teilgebiet nach erfolgreichem Output und Freigabe durch Thomas abschließen (R2-OK von Thomas: Status auf „abgeschlossen" im zentral-index.md). ## Artefakte @@ -153,10 +186,11 @@ Die in S04 mit docx-js erstellte Version hatte strukturelle typographische Mäng - `artefakte/01-lebenslauf/source/cv.md` — **Aktive Quelldatei** (aufbauend auf V10, Draft-Marker entfernt). - `artefakte/01-lebenslauf/source/foto-wrba_2026_6782_1.jpg` — Portraitfoto (umbenannt, noch nicht in cv.md eingebunden). -- `artefakte/01-lebenslauf/templates/template.tex` — Pandoc-LaTeX-Template für LuaLaTeX (erstes Grundgerüst). -- `artefakte/01-lebenslauf/templates/reference.docx` — Pandoc-Default-Reference-Doc als Ausgangsbasis (Styles noch anzupassen). -- `artefakte/01-lebenslauf/build/build.ps1` — PowerShell-Build-Skript (PDF + DOCX). -- `artefakte/01-lebenslauf/output/` — erzeugte Ausgaben plus `build.log` (leer bis zum ersten erfolgreichen Build). +- `artefakte/01-lebenslauf/templates/template.tex` — Pandoc-LaTeX-Template für LuaLaTeX (Iteration A inkl. Pandoc-3.x-Hotfix `\newcounter{none}`). +- `artefakte/01-lebenslauf/templates/reference.docx` — Pandoc-Reference-Doc, **automatisch erzeugt** durch `build/build-reference-docx.py`. Nicht von Hand editieren — Änderungen würden beim nächsten Skript-Lauf überschrieben. +- `artefakte/01-lebenslauf/build/build-reference-docx.py` — Python-Skript zum Bauen der `reference.docx` (Iteration B1+B1.5+B2). Manuell aufrufen, wenn Stile geändert werden sollen, danach normalen `build.ps1` laufen. +- `artefakte/01-lebenslauf/build/build.ps1` — PowerShell-Build-Skript (PDF + DOCX) mit 3-Sekunden-Pause bei Fehler. +- `artefakte/01-lebenslauf/output/` — erzeugte Ausgaben plus `build.log`. ### Historische Entwürfe (unter `artefakte/01-lebenslauf/entwuerfe/`)