Skip to content

feat: implement catalog ingredient file upload and voice-memo capture (#2038)#2079

Merged
atomantic merged 2 commits into
mainfrom
claim/issue-2038
Jul 2, 2026
Merged

feat: implement catalog ingredient file upload and voice-memo capture (#2038)#2079
atomantic merged 2 commits into
mainfrom
claim/issue-2038

Conversation

@atomantic

Copy link
Copy Markdown
Owner

Closes #2038

Summary

Replaces the two "coming soon" stubs on the CatalogIngredient Media panel with working file-upload and voice-memo capture, both attaching through the existing onAttach(mediaKey, kind) seam and federating like gallery attachments.

What shipped

  • File upload — drag-drop of a real OS file (not just an in-app gallery tile) plus an "Upload file" picker on the Media panel. New POST /catalog/ingredients/:id/media/upload stores the file in the matching federating library dir (image→data/images as PNG via the existing gallery saver, audio→data/audio, video→data/videos), then attaches it. The server derives the media kind from the MIME; documents are rejected (no federating dir → would break references on peers).
  • Voice memo — a "Record memo" button reuses startMemoRecording (MediaRecorder → 16 kHz mono WAV, mobile Safari/Chrome friendly). New POST /catalog/ingredients/:id/media/voice transcribes via the existing Whisper pipeline and attaches a kind:'audio' row with the transcript in caption (persist happens after transcription, so a failed transcript never orphans a file).
  • Federation — automatic and unchanged: catalogSync ships the media_key reference, peerMediaLibrarySync ships the bytes (audio/video dirs already replicate). No hashImageForManifest call needed at the attach site.
  • UI — audio/video attachments now render inline players in MediaTile; both "coming soon" toasts and the stale tracking comment removed.
  • Zod schemas (catalogMediaFileUploadSchema / catalogMediaVoiceMemoSchema) wired into both new routes.

Files

  • server/services/catalogMedia.js (new) + catalogMedia.test.js (new, 13 tests)
  • server/routes/catalog.js, server/lib/catalogValidation.js
  • client/src/pages/CatalogIngredient.jsx, client/src/services/apiCatalog.js
  • .changelog/NEXT.md

Test plan

  • npx vitest run services/catalogMedia.test.js → 13 pass (mime classification + upload/voice orchestration with injected deps — no DB/disk/Whisper).
  • lib/catalogValidation.test.js → 100 pass; routes/catalog.test.js correctly skips on the real portos DB (safety gate).
  • Client: CatalogIngredient.test.jsx → 21 pass, ESLint clean, production build succeeds.

https://claude.ai/code/session_01M1aQgtbUZZ9WmE9V6XyT8Q

atomantic added 2 commits July 2, 2026 11:56
…#2038)

Replace the two "coming soon" stubs on the CatalogIngredient Media panel with
working file-upload and voice-memo capture.

- New POST /catalog/ingredients/:id/media/upload persists a dropped/picked file
  into the matching federating library dir (image->data/images as PNG via the
  existing gallery saver, audio->data/audio, video->data/videos) and attaches it
  via the existing media-refs seam. Server picks the media kind from the MIME;
  documents are rejected (no federating dir -> would break peer references).
- New POST /catalog/ingredients/:id/media/voice transcribes a recorded WAV via
  the existing Whisper pipeline and attaches a kind:'audio' row with the
  transcript in caption (persist after transcription; no orphan on failure).
- Both routes Zod-validated (catalogMediaFileUploadSchema / catalogMediaVoiceMemoSchema).
- Client: drag-drop of real files, Upload-file picker, Record-memo button
  (reusing startMemoRecording), inline audio/video players in MediaTile, and the
  two "coming soon" toasts removed. Federation is automatic (catalogSync ships
  the reference, peerMediaLibrarySync ships the bytes).
- Unit tests for the new service (mime classification + upload/voice orchestration
  with injected deps).

Claude-Session: https://claude.ai/code/session_01M1aQgtbUZZ9WmE9V6XyT8Q
@atomantic atomantic merged commit 918680d into main Jul 2, 2026
2 checks passed
@atomantic atomantic deleted the claim/issue-2038 branch July 2, 2026 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Catalog ingredient media: implement file upload and voice-memo capture (currently 'coming soon' stubs)

1 participant