Media — Document pick, preview, OCR, formats (privacy + widgets)
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*emengines/sdk/koder_kit— nunca rolarfile_pickerupstream 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:
- *CR*(
media.document.ocr) — toggle: ON habilita extração detexto de imagens
- *CR backend*(
media.document.ocr_backend) — dropdown:local(tesseract embarcado),koder(services/ai/ocr),auto(local-first, fallback Koder) - *CR idioma padrão*(
media.document.ocr_lang) — dropdown:auto(detect) /pt-BR/en-US/es-ES/ etc. - *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* | Privacy |
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/ocrself-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(nuncafile_pickerupstream 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 é:
KoderImagePicker.camera()→KoderImageRef- App chama
KoderOcrButton(imageRef)→Stringtexto extraído - App pode tratar texto como busca, autofill de form, ou salvar como
KoderDocumentRefMD
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 daKoder 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