Captura, picker, preview, crop e upload de fotos. EXIF strip ON por default; widgets KoderImagePicker / KoderImagePreview / KoderImageCropper.
Documento
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.
Especificação completa
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 todo app Koder que aceite, exiba, ou faça OCR de documentos: anexar PDF/DOCX/MD/KMD/TXT/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. TV/CLI/TUI fora de scope (sem use case típico).
1 — MUST: expose "Documento" toggle group in Settings
Sub-seção "Documento" do agrupamento "Mídia"; deve conter, na ordem:
- OCR (
media.document.ocr) — toggle: ON habilita extração de texto de imagens - OCR backend (
media.document.ocr_backend) — dropdown:local(tesseract embarcado),koder(services/ai/ocr),auto(local-first, fallback Koder) - OCR idioma padrão (
media.document.ocr_lang) — dropdown:auto(detect) /pt-BR/en-US/es-ES/ etc. - Preview 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 | OFF | Privacy-by-default; 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 | ON | Preview inline reduz friction; documents podem ser previewed sem download |
3 — MUST: privacidade
- NUNCA auto-upload de documento (user confirma antes do POST)
- OCR 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) - NUNCA OCR via serviços terceiros (Google Cloud Vision, AWS
Textract, Azure Form Recognizer) — apenas tesseract local OU
services/ai/ocrself-hosted - NUNCA persistir texto extraído em telemetria, error report,
breadcrumb — apenas counter
media.document.ocr_done - Preview de PDF in-app deve 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
Suportados (pick + preview): PDF, DOCX, ODT, MD, KMD (Koder Markdown — superset de MD usado em specs/RFCs/policies; mesmo renderer de MD com extensões Koder), TXT, RTF, EPUB, HTML (sandboxed).
OCR-able: JPEG, PNG, WebP, AVIF, HEIC, PDF (com imagem embarcada — extract pages → run OCR per page).
Not supported (rejected ao pick): executáveis (.exe, .dmg, .app), arquivos compactados quando não whitelisted, MIME types desconhecidos.
Upload 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 - Nã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, page_count, size_bucket)
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(privacy-by-default §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 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
Outras capabilities de mídia
Gravação, playback e screen-capture. Recording indicator obrigatório; codecs via engines/kodec; widgets KoderVideoPlayer / KoderVideoRecorder / KoderScreenCapture.
Memos, podcast, attachments e ringtones — áudio genérico, separado de voice/wake-word. Widgets KoderAudioPlayer / KoderAudioRecorder.