# copilot-export

> Module created via `npm run new:module copilot-export`.

## Owner

SupplierPulse / Copilot-Exporte (Demo-067 C/E, KAR-982/KAR-984)

## Purpose

Builds the four "Copilot-Export" documents (Fabrikanalyse / QAF-Vergleich /
Wertstrom / Gesamtprojekt) a consultant can load into an external LLM tool
and keep working with — DOCX and Markdown (all four; Markdown added
Demo-067 E, KAR-984, for the "paste into an AI chat" workflow) and, for the
Gesamtprojekt-Export, also XLSX. Every export opens with a shared
AI-instruction block (what the document is, how to work with it, an
LSC/QAF/VSM/FA glossary) and, only for `is_demo` projects, a fictional-data
disclaimer. The DOCX and Markdown rendering of the same export share the
same input contract and section order — only the markup differs.

Feature-gated behind `copilotExports` (`config/profiles/`) — `true` in `bmw`,
`false` in `default`/`_template`.

## Public API

The public surface is the named exports of `index.ts`. Anything in
`internal/` is private and may change without notice.

- `buildFabrikanalyseCopilotDocx(input: AssessmentDocxInput): Promise<Buffer>`
- `buildFabrikanalyseCopilotMd(input: AssessmentDocxInput): string`
- `buildQafComparisonCopilotDocx(input: QafComparisonDocxInput): Promise<Buffer>`
- `buildQafComparisonCopilotMd(input: QafComparisonDocxInput): string`
- `buildWertstromCopilotDocx(input: WertstromDocxInput): Promise<Buffer>`
- `buildWertstromCopilotMd(input: WertstromDocxInput): string`
- `buildProjectCopilotDocx(input: ProjectExportInput): Promise<Buffer>`
- `buildProjectCopilotMd(input: ProjectExportInput): string`
- `buildProjectCopilotXlsx(input: ProjectExportInput): Promise<ArrayBuffer>`
- `copilotExportsGate(enabled: boolean)` — pure flag-gate predicate; callers
  pass `getProfile().features.copilotExports` in.
- `fictionalDataDisclaimer(isDemo: boolean): string | null`
- `sanitizeFilenamePart(value, fallback): string`
- `formatNumberDe(value, fractionDigits?): string`

Markdown builders are synchronous (`string`, not `Promise<Buffer>`) — unlike
DOCX/XLSX there is no pack/serialize step, so wrapping the return in a
Promise would add nothing.

## Dependencies

- `docx` (new, Demo-067 C) — DOCX generation.
- `exceljs` (existing) — the Gesamtprojekt-Export's XLSX sheet.
- `@/lib/assessment-analytics`, `@/lib/assessment-types` — Fabrikanalyse stats/types (read-only reuse, no changes).
- `@/lib/qaf-differences` (public barrel only) — `QafComparisonResult` type; the caller rehydrates the comparison via that module's own `rehydrateExportInput`, this module only renders the already-computed result.
- `@/lib/vsm-types` — `ValueStreamMap`/`VsmNode` types.
- `@/components/wertstrom/vsm-metrics` — derived VSM KPIs (VA-Quote, time sums, cost rollups), reused so the export always matches what the editor shows on screen.

Deliberately NOT a dependency: Supabase. Every builder is a pure function of
plain data — the server actions under `app/` (two per module — DOCX/Markdown;
three for the Gesamtprojekt-Export) do all DB I/O and feature-flag gating,
then call into this module.

## Markdown builders (Demo-067 E, KAR-984)

`assessment-md.ts`/`qaf-md.ts`/`wertstrom-md.ts`/`project-md.ts` consume the
exact same `*DocxInput`/`ProjectExportInput` contracts as their DOCX
siblings and render the same content/order — only the markup changes
(Markdown headings + GFM pipe-tables via `md-shared.ts`, instead of `docx`
Paragraph/Table). The DOCX builders were deliberately left untouched (no
shared content-model refactor): format-neutral helpers already living
outside the DOCX builder files are reused as-is (`formatNumberDe`/
`formatPercentDe`/`sanitizeFilenamePart` in `docx-shared.ts`,
`buildAiInstructionBlock` in `ai-instruction-block.ts`, the Stammdaten/
Maßnahmen row helpers in `project-content.ts`); small helpers that live
*inside* a DOCX builder file (rating labels, node-type labels, delta
formatting) are duplicated 1:1 into the matching MD builder, the same
duplication style `assessment-docx.ts` itself already uses for
`toResponseDraftMap`.

## Tests

`copilot-export.test.ts` next to this README (entrypoint smoke test) plus
`__tests__/*.test.ts` — one file per builder, each with a real roundtrip
(DOCX via `docx` + JSZip unzip of `word/document.xml`; XLSX read back via
`exceljs`; Markdown asserted directly on the returned string), plus the
AI-instruction-block/flag-gate/disclaimer unit tests.
Run via `npm test -- copilot-export`.

## Conventions (ADR 019)

- No deep imports into other modules' `internal/` directories.
- This module never imports from `lib/customers/**` (ADR 010 / ADR 015).
- Customer-specific behaviour goes via the active composition profile (ADR 013).
- No customer name (e.g. the pilot customer's name) appears in any string
  literal in this module (`scripts/check-forbidden-strings.mjs`) — glossary
  wording is customer-generic even though the underlying concepts come from
  `docs/GLOSSARY.md`.


> Seit Loop 12 (Export-Profil-Versionierung) importiert dieses Modul aus
> `@/lib/qaf-differences` auch einen **Wert** (`exportProfileStampLineDe`),
> nicht mehr nur Typen — der Versions-Stempel im Kopf von MD/DOCX kommt aus
> dem einen Exportprofil-Register.
