[feat-010] Pre-render PDFs at upload + shimmer chip + send-button gate

↗ view on GitHub · Nick Whitehouse · 2026-05-06 · b2840147

After a PDF upload completes, fire a fire-and-forget vision pre-render
in the background. By the time the user opens a chat against the doc,
the R2 cache is warm and the chat skips the ~10s pdftoppm cost
entirely. Combined with feat-009's caches, first chat against a
freshly-uploaded doc is now near-instant from the user's perspective.

UX:
  - Attachment chip in ChatInput shows immediately on attach
  - Shimmer overlay (chip-shimmer keyframe in globals.css) plays while
    pre-render is in flight - clear visual signal that the chat isn't
    quite ready yet
  - Send button disabled while ANY attached PDF is pending; tooltip
    explains why. Belt-and-braces in handleSubmit so Enter doesn't
    sneak past the disabled button

Backend:
  - lib/visionPrerender.ts: in-process pending-renders map + R2 lookup
    fallback so status survives restarts. kickOffVisionPrerender is
    idempotent (no-op if already pending or ready).
  - routes/documents.ts (handleDocumentUpload + version upload):
    fire-and-forget kick-off after the documents.update completes.
    Only PDFs - DOCX vision mode isn't wired.
  - routes/projects.ts (project upload): same.
  - GET /single-documents/:id/vision-status: returns
    {status: pending|ready|failed|missing}. Cheap - combines memory
    map with R2 manifest existence check.

Frontend:
  - hooks/useVisionStatus.ts: polls vision-status every 1s per attached
    PDF until status resolves; caps at 60 attempts so the UI never
    locks if the backend goes weird.
  - ChatInput uses the hook to drive shimmer + button-disable.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Repository nwhitehouse/mike
Author Nick Whitehouse <nick.whitehouse@mccarthyfinch.com>
Authored
Parents 4f480f20
Stats 6 files changed , +453 , -3
Part of Vision mode: PDF page images → Olava (feat-007a / 008 / 009 / 010 / bug-005)

Capture this commit into my fork

Download a Markdown prompt that tells Claude how to port this exact commit into your working tree. Run it via claude -p < capture-commit-b2840147.md from inside the repo you want the change in.

⬇ Download capture-commit-b2840147.md