- **Optional pre-parse file-to-PDF converter pipeline stage powered by Gotenberg.** New pipeline component family (`file_converter`): `BaseFileConverter` (`opencontractserver/pipeline/base/file_converter.py`) + `GotenbergFileConverter` (`opencontractserver/pipeline/file_converters/gotenberg_converter.py`), which converts every extension Gotenberg's LibreOffice route supports *except* the natively-parsed formats (pdf, txt, docx, md) — so `.doc`, `.rtf`, `.odt`, `.ppt(x)`, `.xls`, `.html`, iWork formats, etc. become PDFs before parsing, while `.docx` keeps its native parser path. Highlights:
  - New `convert_document_to_pdf` Celery task at the head of both ingest chains (`documents/signals.py`, `tasks/doc_tasks.py::retry_document_processing`) so thumbnails and parsers see the converted PDF; failures mark the document FAILED with the real conversion error and halt the chain (`FileConversionError` carries the transient/permanent retry contract).
  - Original uploads are preserved: `Document.original_file` / `original_file_type` keep a reference to the pre-conversion blob (no byte copy); `pdf_file` is replaced with the converted PDF, `file_type` flips to `application/pdf`, and `pdf_file_hash` is refreshed (migration `documents/0043_add_file_converter_support.py`).
  - Admin selection + configuration: `PipelineSettings.default_file_converter` (empty = disabled), exposed via GraphQL (`pipelineComponents.fileConverters`, `pipelineSettings.defaultFileConverter`, `updatePipelineSettings(defaultFileConverter:)` with converter-type validation) and the `/system_settings` admin UI (new File Converter row + picker modal, Component Library stage with schema-driven `service_url` / `request_timeout` / `convert_extensions` settings).
  - Converter-aware upload acceptance: `resolve_convertible_upload` (`opencontractserver/pipeline/utils.py`) admits configured extensions through `import_document_for_user`, `DocumentService.validate_file_type`, and both zip-import paths; extension list is admin-configurable via the converter's `convert_extensions` setting (empty = all supported).
  - New `gotenberg` service (`gotenberg/gotenberg:8`) in `local.yml` and `production.yml` (bridge-only at `http://gotenberg:3000`, `required: false` dependency), with `GOTENBERG_SERVICE_URL` / `GOTENBERG_CONVERTER_TIMEOUT` / `DEFAULT_FILE_CONVERTER` settings in `config/settings/base.py`.
  - Security posture: convertible uploads are stored with an inert `application/octet-stream` `file_type` (never a browser-renderable type) so there is no stored-XSS window before conversion; the pre-conversion source blob is retained on the internal-only `Document.original_file` field (excluded from `DocumentType`). The Gotenberg/LibreOffice SSRF surface (LibreOffice can fetch remote resources referenced by a document) is documented in `docs/pipelines/pipeline_overview.md` — restrict the `gotenberg` container's egress in sensitive deployments; it needs no outbound access.
  - Converter-aware upload UI: new `convertibleExtensions` GraphQL query drives the upload modal's accepted-format set (`UploadModal`/`FileDropZone`) so convertible formats are actually selectable, summarized rather than enumerated.
  - Original-file provenance travels with corpus copies (`Corpus.add_document`) and corpus forks (`fork_tasks.py`), keeping the pre-conversion blob referenced for delete-time GC.
  - Tests in `opencontractserver/tests/test_file_converters.py`; docs in `docs/pipelines/pipeline_overview.md` (File Converters section).
