Media — Document pick, preview, OCR, formats (privacy + widgets)

mandatory

Contrato cross-surface para seleção, preview, e OCR de documentos em apps Koder (PDF, DOCX, MD, KMD, TXT, ODT). Toggles em Settings (`media.document.ocr`); defaults seguros; widgets `KoderDocumentPicker` + `KoderDocumentPreview` + `KoderOcrButton` em `engines/sdk/koder_kit`. OCR roda local-first via tesseract ou serviço Koder (`services/ai/ocr` quando disponível) — terceiros proibidos. Upload size cap 50 MB. `<APP>-DOC-*` error map. **Bridge com `image.kmd`:** captura via câmera retorna `KoderImageRef`; OCR vira o passo seguinte (image → text) e o resultado é tratado como document.

Media — Document Spec — v0.1

Normative cross-surface spec para document I/O em apps Koder (incluindo OCR como bridge image→text). Implementação obrigatória via widgets KoderDocument* em engines/sdk/koder_kit — nunca rolar file_picker upstream ou <input type="file" accept=".pdf"> raw local.


Scope

Aplica-se a *odo app Koder que aceite, exiba, ou faça OCR de documentos* anexar PDFDOCXMDKMDTXT/ODT em chat ou formulário, preview inline (sem download), upload de resume/contract, OCR de foto (recibo, RG, contrato) para extração de texto.

Surfaces cobertas: Flutter mobile (Android + iOS), Flutter desktop (Linux + macOS + Windows), Flutter web ou templ+HTMX. TVCLITUI fora de scope (sem use case típico).


1 — MUST: expose "Documento" toggle group in Settings

Sub-seção "Documento" do agrupamento "Mídia"; *eve*conter, na ordem:

  1. *CR*(media.document.ocr) — toggle: ON habilita extração de

    texto de imagens

  2. *CR backend*(media.document.ocr_backend) — dropdown:

    local (tesseract embarcado), koder (services/ai/ocr), auto (local-first, fallback Koder)

  3. *CR idioma padrão*(media.document.ocr_lang) — dropdown:

    auto (detect) / pt-BR / en-US / es-ES / etc.

  4. *review de PDF inline*(media.document.pdf_preview) — checkbox;

    default ON; OFF força download


2 — MUST: defaults seguros em fresh install

Chave Default Notas
media.document.ocr *FF* Privacybydefault; OCR consome bateria e (se backend=koder) envia imagem; opt-in
media.document.ocr_backend local Local-first; user pode trocar pra koder ou auto
media.document.ocr_lang auto Tesseract detecta; user pode forçar idioma específico
media.document.pdf_preview *N* Preview inline reduz friction; documents podem ser previewed sem download

3 — MUST: privacidade

  • *UNCA*auto-upload de documento (user confirma antes do POST)
  • *CR local-first*quando viável: tesseract embarcado roda sem

    network call; services/ai/ocr é fallback (precisa OK explícito via toggle backend=koder ou auto)

  • *UNCA*OCR via serviços terceiros (Google Cloud Vision, AWS

    Textract, Azure Form Recognizer) — apenas tesseract local OU services/ai/ocr self-hosted

  • *UNCA*persistir texto extraído em telemetria, error report,

    breadcrumb — apenas counter media.document.ocr_done

  • Preview de PDF in-app *eve*sanitizar JS embarcado (PDF.js

    com disableExternalLinks: true)


4 — MUST: widget surface no koder_kit

Widget Função
KoderDocumentPicker File picker filtered ao MIME suportado; retorna KoderDocumentRef
KoderDocumentPreview Preview inline (PDF.js no web; pdf_render em Flutter; nativo em iOS/Android Quick Look)
KoderOcrButton Trigger OCR sobre KoderImageRef ou KoderDocumentRef; retorna String ou OcrError
KoderDocumentThumbnail Render de primeira página como thumb 256px

KoderDocumentRef: {uri, mime, sizeBytes, pageCount?, title?, koderUserId?, workspaceId?}.


5 — MUST: format support

*uportados (pick + preview):*PDF, DOCX, ODT, MD, *MD*(Koder Markdown — superset de MD usado em specsRFCspolicies; mesmo renderer de MD com extensões Koder), TXT, RTF, EPUB, HTML (sandboxed).

*CR-able:*JPEG, PNG, WebP, AVIF, HEIC, PDF (com imagem embarcada — extract pages → run OCR per page).

*ot supported (rejected ao pick):*executáveis (.exe, .dmg, .app), arquivos compactados quando não whitelisted, MIME types desconhecidos.

*pload size cap:*50 MB. Exceder → <APP>-DOC-SIZE-001.


6 — MUST: error surface

Cenário ID Texto pt-BR
Formato não suportado <APP>-DOC-FMT-001 "Este tipo de arquivo não é suportado."
Tamanho excede 50 MB <APP>-DOC-SIZE-001 "Documento muito grande. Reduza páginas ou comprima."
Preview falhou (corrupto / encriptado) <APP>-DOC-PRV-001 "Não foi possível visualizar este documento."
OCR falhou (idioma não disponível local) <APP>-DOC-OCR-001 "OCR não disponível para este idioma. Tente backend Koder."
OCR backend Koder indisponível <APP>-DOC-OCR-NET-001 "Serviço de OCR indisponível. Tente novamente."
Upload falhou <APP>-DOC-NET-001 "Falha ao enviar o documento. Tente novamente."
Arquivo rejeitado (executável / suspeito) <APP>-DOC-SEC-001 "Este tipo de arquivo não pode ser anexado por segurança."

7 — Observability

  • Counters: media.document.picked, media.document.uploaded,

    media.document.ocr_done, media.document.ocr_error, media.document.preview_failed

  • Latency histograms: media.document.upload_ms,

    media.document.ocr_ms, media.document.preview_render_ms

  • *ão*emitir métricas que vazem conteúdo (page text, file path,

    título do documento, hash) — apenas counters + latência + dimensões anônimas (mime, pagecount, sizebucket)


8 — Adoption checklist (per app)

  • [ ] Importa KoderMediaSettingsTile (sub-seção Documento visível)
  • [ ] Usa KoderDocumentPicker (nunca file_picker upstream raw)
  • [ ] Defaults da §2 respeitados
  • [ ] OCR backend default local (privacybydefault §3)
  • [ ] Formats da §5 respeitados (executáveis rejeitados)
  • [ ] Error map da §6 implementado
  • [ ] Upload path respeita multi-tenancy/contract.kmd
  • [ ] Se OCR ativo: services/ai/ocr é único cloud backend permitido

Bridge com image.kmd

Quando o user tira foto de documento (cartão, contrato) com a câmera, o flow é:

  1. KoderImagePicker.camera()KoderImageRef
  2. App chama KoderOcrButton(imageRef)String texto extraído
  3. App pode tratar texto como busca, autofill de form, ou salvar como

    KoderDocumentRef MD

Não é necessário converter KoderImageRef em KoderDocumentRef — o OCR widget aceita ambos diretamente. Para document scanning multi-page (várias fotos → 1 PDF), usar KoderDocumentScanner (helper de alto nível que combina image.camera() em loop + auto-crop + merge PDF).


Non-normative — referências

  • Sibling specs: specs/media/image.kmd (camera bridge),

    specs/media/video.kmd, specs/media/audio.kmd

  • OCR backend self-hosted: services/ai/ocr/ — futuro componente da

    Koder Stack; até existir, local (tesseract) é o único permitido

  • Implementation surface: engines/sdk/koder_kit/lib/src/media/
  • Voice precedent (privacy contract): specs/voice/wake-word.kmd

Source: ../home/koder/dev/koder/meta/docs/stack/specs/media/document.kmd